FC2カウンター FPGAの部屋 2015年10月

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

FPGAの部屋

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

ZYBOにHDLで書いたラプラシアンフィルタを実装する6(Vivado のブロックデザインにIPを追加)

ZYBOにHDLで書いたラプラシアンフィルタを実装する5(IP化)”の続き。

前回は、HDLで書いたラプラシアンフィルタIP をIP化することができたので、今回は、”IPをVivadoのIPIに追加して、BOOT.binとデバイスツリーを作り、ZYBO のLinuxでアプリケーションを作る作り方”のVivado 2015.3 のプロジェクトのブロックデザインに追加する。(V_ZYBO_CAMDfL144_tu_2 をコピーしてVivado 2015.3 のプロジェクトとした)

・現在のフォルダ名を V_ZYBO_CAMDfL153_tu_HDL に変更した。

・Flow Navigator -> Project Manager -> IP Catalog をクリックして、IP Catalog を表示した。
lap_fil_HDL_axim_67_151031.png

・右のウインドウにIP Catalog が出るので、どこでも良いから右クリックして、右クリックメニューから IP Setting... を選択した。

・Project Settings ダイアログが立ち上がった。IP が指定されていた。
・Repository Manager タブをクリックすると、IP Repositories に自分で追加したIP が入っていた。
lap_fil_HDL_axim_68_151031.png

・+ボタンをクリックして、IP Repositories にHDL で書いたラプラシアンフィルタIP を追加する。
・lap_fil_HDL_axim フォルダを選択した。
lap_fil_HDL_axim_69_151031.png

・Add Repository ダイアログが表示された。
lap_fil_HDL_axim_70_151031.png

・lap_fil_HDL_axim IP が IP Repositories に追加された。
lap_fil_HDL_axim_71_151031.png

・IP Catalog に lap_fil_HDL_axim IP が追加された。
lap_fil_HDL_axim_72_151031.png

・V_ZYBO_CAMDfL ブロックデザインを開いた。

・Add IP ボタンをクリックして lap_fil_hdl_axim_V1_0 を追加する。
lap_fil_HDL_axim_73_151031.png

・lap_fil_hdl_axim_V1_0 が追加された。
lap_fil_HDL_axim_74_151031.png

・右上のRun Connection Automation をクリックして、lap_fil_hdl_axim_V1_0 の配線を自動接続する。

・Run Connection Automation が表示された。
・All Automation にチェックを入れた。
・M_AXI を選択して、Slave を /processing_system7_0/S_AXI_HP2 を選択した。
lap_fil_HDL_axim_75_151031.png

・s_axi_lite を選択して、/processing_system7_0/M_AXI_GP0 が選択されているのを確認した。
lap_fil_HDL_axim_76_151031.png

・AXI_Interconnect のポートが自動的に増えて、lap_fil_hdl_axim_V1_0 が自動的に接続された。
lap_fil_HDL_axim_77_151031.png

・Regenerate Layout ボタンをクリックして、レイアウトを再生成した。
lap_fil_HDL_axim_78_151031.png

・Address Editor を示す。
lap_fil_HDL_axim_79_151031.png

lap_fil_hdl_axim_V1_0 は、Axi Lite Slave として、0x43C30000 番地にマップされた。

・ブロックデザインをセーブした。

・ウインドウをドックした時の、プロジェクトを示す。(Vivado 2015.3 を使用)
lap_fil_HDL_axim_80_151031.png
  1. 2015年10月31日 04:30 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

IPをVivadoのIPIに追加して、BOOT.binとデバイスツリーを作り、ZYBO のLinuxでアプリケーションを作る作り方

ZYBOにHDLで書いたラプラシアンフィルタを実装する5(IP化)”でHDL で書いたラプラシアンフィルタをIP にすることができた。

これからVivado プロジェクトのIP Integrator のブロックデザインにHDL で書いたラプラシアンフィルタIP を追加して、論理合成、インプリメントを行い、SDKにハードウェアをエクスポートして、FSBLとビットストリームとU-boot でBOOT.bin を生成する。
また、Linux で zynq-zybo.dts にHDL で書いたラプラシアンフィルタIPのエントリを追加して、コンパイルしてdevicetree.dtb を生成する。
BOOT.bin とdevicetree.dtb をUbuntu 14.04 のRoot file system が入ったSDカードのMS DOSパーティションに入れて、ZYBOに入れてUbuntu 14.04 をブートする。
ZYBO のUbuntu 上で、アプリケーションをVivado HLS で生成されたドライバを使用して作製する。

このような手順で作製していくのだが、この手順を忘れてしまった。
そこで、もう一度おさらいしようと思う。

まずは、Vivado HLS 2014.4 で生成したラプラシアンフィルタIP をカメラ・コントローラIP やビットマップ・ディスプレイ・コントローラIP が接続れたブロックデザインに入れて、ZYBO のUbuntu 上でアプリケーションを作った時のFPGAの部屋の記事をまとめる。

Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする3(IP Catalog にVivado HLSのIPを追加)
Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする4(ブロックデザインにVivado HLSのIPを追加、インプリメント)
Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする5(BOOT.bin, devicetree.dtb の生成)
Vivado HLS 2014.4でラプラシアン・フィルタ関数をaxi masterモジュールにする6(/sys, /devディレクトリ)
Vivado 2014.4のCドライバーファイル1 
Vivado 2014.4のCドライバーファイル2
ZYBO Linux (Ubuntu 14.04 LTS) 上でMakefile を作ってラプラシアンフィルタIPの制御ソフトをコンパイル
ZYBO Linux (Ubuntu 14.04 LTS) 上でMakefile を作ってラプラシアンフィルタIPの制御ソフトをコンパイル2

これで、ラプラシアンフィルタIP をVivado のブロックデザインに入れて、Linux上で動作される方法は終了なのだが、現状の最新プロジェクトはどうなのかというと、おるさんのコードを元に、tu1987さんが書いてくれたC++ソースコードをVivado HLS 2014.4 で高位合成し、IP化したプロジェクトが最新となっている。
Vivado HLS 2014.4 で合成したラプラシアンフィルタIPの高速化16(性能が最大になる設定を探る8、追加2)

このプロジェクトでは、ラプラシアンフィルタのみの処理時間は 15.3 ms となった。
但し、タイミングエラーが出ているので、インプリメント時のStrategy を変更してインプリメントを行う方法で複数のインプリメントを実行して、一番良い物を使う方法でインプリメントを行った。
Vivado 2014.4 でインプリメント時にStrategy を変更してインプリメント結果を改善する

ブログにログが残っていると本当に助かる。。。自分でも。
ログ残っていなかったら、やり方を再度検索する必要がある。ブログは自分にとって、欠かせない補助記憶だ。。。

V_ZYBO_CAMDfL_tu_2フォルダのプロジェクトをVivado 2015.3 のプロジェクトに変換してインプリメントを行った結果を下に示す。
lap_fil_HDL_axim_66_151030.png

やはり、通常にインプリメントしたのでは、タイミングエラーが発生している。
  1. 2015年10月30日 04:50 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0

Adafruit の2.8インチのタッチ付き液晶ディスプレイが届いた

昨日、Adafruit の2.8インチのタッチ付き液晶ディスプレイが届いた。

Arduino のコネクタに嵌合するヘッダが付いているタッチ付き液晶ディスプレイだ。
これは、Rocketboards.org の OpenCL Mandelbrot Demo on Atlas-SoC をやるために購入した。

Adafruit に2015年の10月15日に注文して、2015年の10月28日に届いた。13日で届いたの優秀だと思うが、トラッキングが酷かった。

Shipping は USPS (United States Postal Service) でお願いしたのだが、トラッキングはジャマイカに届いたということになっているので、とっても心配した。
Adafruit にメールしたのだが、USPSのトラッキングは当てにならないということだった。ドキドキだったが届いて良かった。

価格はタッチ付き液晶ディスプレイが $34.95 、Shipping が $12.85 で合計 $47.80 だった。Paypal で支払いをしたが、日本円で 5,908 円だった。

これで、DE0-Nano-SoC でマンデルブローが試せる。OpenCLのライセンスが無いので、コンパイルは出来ないのが残念だが。。。

DE0-Nano-SoC_57_151029.jpg

DE0-Nano-SoC_58_151029.jpg

DE0-Nano-SoC_59_151029.jpg
  1. 2015年10月29日 04:50 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:4

ZYBOにHDLで書いたラプラシアンフィルタを実装する5(IP化)

ZYBOにHDLで書いたラプラシアンフィルタを実装する4(シミュレーション)”の続き。

前回、シミュレーションで動作を確認できたので、今回はIP化を行う。使用するVivado のバージョンは 2015.3 だ。

Tools メニューから Create and Package IP... を選択する。

Create and Package IP.ダイアログが開いた。
lap_fil_HDL_axim_51_151027.png

Create Peripheral, Package IP or Package a Block Design
lap_fil_HDL_axim_52_151027.png

Package Your Curent Project
lap_fil_HDL_axim_53_151027.png

New Creation
lap_fil_HDL_axim_54_151027.png

Package IP ウインドウの Identification が開いた。
lap_fil_HDL_axim_55_151027.png

Compatibility
lap_fil_HDL_axim_56_151027.png

File Groups
lap_fil_HDL_axim_65_151027.png

Customization Prameters
lap_fil_HDL_axim_57_151027.png

Ports and Interfaces
lap_fil_HDL_axim_58_151027.png

Addressing and Memory は warning が出ていた。
lap_fil_HDL_axim_59_151027.png

Addressing and Memory の Range Dependency を ”pow(2,12)”に変更したら、warning は無くなった。
lap_fil_HDL_axim_60_151027.png

Customization GUI
lap_fil_HDL_axim_61_151027.png

Review and Package で、Package IP ボタンをクリックした。
lap_fil_HDL_axim_62_151027.png

Package IP ダイアログが出て、成功したそうだ。
lap_fil_HDL_axim_63_151027.png

IP化できた。
lap_fil_HDL_axim_64_151027.png
  1. 2015年10月28日 04:38 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBOにHDLで書いたラプラシアンフィルタを実装する4(シミュレーション)

ZYBOにHDLで書いたラプラシアンフィルタを実装する3(FIFO の生成3)”の続き。

前回で、FIFO IPの生成は終了した。今回は、シミュレーションを行う。

最初に、自作した Verilog HDLソースコードを示す。Verilog HDLソースコードは以前と同じだが、トップの名前を lap_filter_axim.v から lap_fil_hdl_axim.v に変更した。モジュール名も lap_fil_hdl_axim に変更した。

Verilog HDL ソースコードは、以下の記事のあるので、参考にされたい。
AXI4 Master アクセスのラプラシアン・フィルタ IP5(lap_filter_axim.v のHDLソース)
AXI4 Master アクセスのラプラシアン・フィルタ IP6(lap_filter_axim_LiteS_if.v のHDLソース)
AXI4 Master アクセスのラプラシアン・フィルタ IP6(line_read_and_y.v と Dual_Port_Memory.v)
AXI4 Master Interfaceモジュールの作製4(axi4_master_inf.v のHDLソース)

テストベンチ用の axi_slave_BFM はこちら。
AXI4 Slave Bus Functional Model のVerilog HDL版2
シミュレーション用 同期FIFO IP

テストベンチはすでに作ってあるので、Vivado 2015.3 でシミュレーションを行った。
lap_fil_HDL_axim_48_151027.png

AXI4 Master の波形を示す。
lap_fil_HDL_axim_49_151027.png

最初に2ラインをAXI4 Master Read して、3ライン目をAXI4 Master Read しながら、ラプラシアンフィルタ演算処理をリアルタイムで行っているので、Read が終了したら、すぐにAXI4 Master Write が始まる。完全にパイプラインされていて無駄はない。
更に、3ライン目の3番目のピクセルデータが来たところからラプラシアンフィルタ処理が始まっているので、すぐにWrite を初められる。つまり、メモリ帯域に空きがあるのが前提だが、更に処理時間を縮める事が可能だ。

1フレームの最後までシミュレーションを行った。約、9.9 ms 程度でラプラシアンフィルタ処理が終了した。
lap_fil_HDL_axim_50_151027.png

テストベンチの lap_fil_hdl_axim_tb.v を貼っておく。

`default_nettype none
`timescale 100ps / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:   2015/10/22
// Design Name:   lap_fil_hdl_axim
// Module Name:   lap_fil_hdl_axim.v
// Project Name:  lap_fil_hdl_axim
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: lap_filter_axim
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////

module lap_fil_hdl_axim_tb;

    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9; // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32; // Data width of the AXI Lite Interface

    parameter DELAY = 1;

    // Inputs
    wire s_axi_lite_aclk;
    wire ACLK;
    wire ARESETN;
    reg s_axi_lite_awvalid;
    reg [8:0] s_axi_lite_awaddr;
    reg s_axi_lite_wvalid;
    reg [31:0] s_axi_lite_wdata;
    reg [3:0] s_axi_lite_wstrb;
    reg s_axi_lite_bready;
    reg s_axi_lite_arvalid;
    reg [8:0] s_axi_lite_araddr;
    reg s_axi_lite_rready;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [31:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;

    // Outputs
    wire s_axi_lite_awready;
    wire s_axi_lite_wready;
    wire [1:0] s_axi_lite_bresp;
    wire s_axi_lite_bvalid;
    wire s_axi_lite_arready;
    wire s_axi_lite_rvalid;
    wire [31:0] s_axi_lite_rdata;
    wire [1:0] s_axi_lite_rresp;
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [31:0] M_AXI_WDATA;
    wire [3:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire interrupt;
    wire write_fifo_overflow;


    // Instantiate the Unit Under Test (UUT)
    lap_fil_hdl_axim # (
            .C_S_AXI_LITE_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
            .C_S_AXI_LITE_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH)
        ) uut (
        .s_axi_lite_aclk(s_axi_lite_aclk),
        .M_AXI_ACLK(ACLK),
        .ARESETN(ARESETN),
        .s_axi_lite_awvalid(s_axi_lite_awvalid),
        .s_axi_lite_awready(s_axi_lite_awready),
        .s_axi_lite_awaddr(s_axi_lite_awaddr),
        .s_axi_lite_wvalid(s_axi_lite_wvalid),
        .s_axi_lite_wready(s_axi_lite_wready),
        .s_axi_lite_wdata(s_axi_lite_wdata),
        .s_axi_lite_wstrb(s_axi_lite_wstrb),
        .s_axi_lite_bresp(s_axi_lite_bresp),
        .s_axi_lite_bvalid(s_axi_lite_bvalid),
        .s_axi_lite_bready(s_axi_lite_bready),
        .s_axi_lite_arvalid(s_axi_lite_arvalid),
        .s_axi_lite_arready(s_axi_lite_arready),
        .s_axi_lite_araddr(s_axi_lite_araddr),
        .s_axi_lite_rvalid(s_axi_lite_rvalid),
        .s_axi_lite_rready(s_axi_lite_rready),
        .s_axi_lite_rdata(s_axi_lite_rdata),
        .s_axi_lite_rresp(s_axi_lite_rresp),
        .M_AXI_AWID(M_AXI_AWID),
        .M_AXI_AWADDR(M_AXI_AWADDR),
        .M_AXI_AWLEN(M_AXI_AWLEN),
        .M_AXI_AWSIZE(M_AXI_AWSIZE),
        .M_AXI_AWBURST(M_AXI_AWBURST),
        .M_AXI_AWLOCK(M_AXI_AWLOCK),
        .M_AXI_AWCACHE(M_AXI_AWCACHE),
        .M_AXI_AWPROT(M_AXI_AWPROT),
        .M_AXI_AWQOS(M_AXI_AWQOS),
        .M_AXI_AWUSER(M_AXI_AWUSER),
        .M_AXI_AWVALID(M_AXI_AWVALID),
        .M_AXI_AWREADY(M_AXI_AWREADY),
        .M_AXI_WDATA(M_AXI_WDATA),
        .M_AXI_WSTRB(M_AXI_WSTRB),
        .M_AXI_WLAST(M_AXI_WLAST),
        .M_AXI_WUSER(M_AXI_WUSER),
        .M_AXI_WVALID(M_AXI_WVALID),
        .M_AXI_WREADY(M_AXI_WREADY),
        .M_AXI_BID(M_AXI_BID),
        .M_AXI_BRESP(M_AXI_BRESP),
        .M_AXI_BUSER(M_AXI_BUSER),
        .M_AXI_BVALID(M_AXI_BVALID),
        .M_AXI_BREADY(M_AXI_BREADY),
        .M_AXI_ARID(M_AXI_ARID),
        .M_AXI_ARADDR(M_AXI_ARADDR),
        .M_AXI_ARLEN(M_AXI_ARLEN),
        .M_AXI_ARSIZE(M_AXI_ARSIZE),
        .M_AXI_ARBURST(M_AXI_ARBURST),
        .M_AXI_ARLOCK(M_AXI_ARLOCK),
        .M_AXI_ARCACHE(M_AXI_ARCACHE),
        .M_AXI_ARPROT(M_AXI_ARPROT),
        .M_AXI_ARQOS(M_AXI_ARQOS),
        .M_AXI_ARUSER(M_AXI_ARUSER),
        .M_AXI_ARVALID(M_AXI_ARVALID),
        .M_AXI_ARREADY(M_AXI_ARREADY),
        .M_AXI_RID(M_AXI_RID),
        .M_AXI_RDATA(M_AXI_RDATA),
        .M_AXI_RRESP(M_AXI_RRESP),
        .M_AXI_RLAST(M_AXI_RLAST),
        .M_AXI_RUSER(M_AXI_RUSER),
        .M_AXI_RVALID(M_AXI_RVALID),
        .M_AXI_RREADY(M_AXI_RREADY),
        .interrupt(interrupt),
        .write_fifo_overflow(write_fifo_overflow)
    );

    initial begin : initial_state
        integer i;

        // Initialize Inputs
        s_axi_lite_awaddr = 0;
        s_axi_lite_awvalid = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_wdata = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_bready = 0;
        s_axi_lite_araddr = 0;
        s_axi_lite_arvalid = 0;
        s_axi_lite_rready = 0;
        s_axi_lite_wstrb = 0;

        // Wait Reset rising edge
        @(posedge ARESETN);

        for (i=0; i<10; i=i+1) begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end

        s_axi_lite_wstrb = 4'b1111;

        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0014, 32'h1000_0000);    // cam_addr write
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0010, 32'h0000_0001);    // cam_addr_ap_vld = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_001C, 32'h2000_0000);    // lap_addr write
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0018, 32'h0000_0001);    // lap_addr_ap_vld = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0008, 32'h0000_0001);    // IP Interrupt Enable Registe(ap_done=1)
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0000, 32'h0000_0001);    // ap_start = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC1(32'h0000_0000);

        forever begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            AXI_MASTER_RADC1(32'h0000_0000);
        end
    end

    // Write Transcation 1
    task AXI_MASTER_WADC1;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid <= 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            s_axi_lite_bready = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Read Transcation 1
    task AXI_MASTER_RADC1;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;

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

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            s_axi_lite_rready = 1'b1;

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

            s_axi_lite_rready = 1'b0;
        end
    endtask

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

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN),
        .init_done()
    );

    // Instantiate the Unit Under Test (UUT_slave)
    axi_slave_bfm # (
        .C_S_AXI_DATA_WIDTH(32),
        .WRITE_RANDOM_WAIT(0),    // Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
        .READ_RANDOM_WAIT(0),    //  Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
        .READ_DATA_IS_INCREMENT(1),    // ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
        .RANDOM_BVALID_WAIT(0),
        .LOAD_RAM_INIT_FILE(1)
    ) uut_slave (
        .ACLK(ACLK),
        .ARESETN(ARESETN),
        .S_AXI_AWID(M_AXI_AWID),
        .S_AXI_AWADDR(M_AXI_AWADDR),
        .S_AXI_AWLEN(M_AXI_AWLEN),
        .S_AXI_AWSIZE(M_AXI_AWSIZE),
        .S_AXI_AWBURST(M_AXI_AWBURST),
        .S_AXI_AWLOCK({1'b0, M_AXI_AWLOCK}),
        .S_AXI_AWCACHE(M_AXI_AWCACHE),
        .S_AXI_AWPROT(M_AXI_AWPROT),
        .S_AXI_AWQOS(M_AXI_AWQOS),
        .S_AXI_AWUSER(M_AXI_AWUSER),
        .S_AXI_AWVALID(M_AXI_AWVALID),
        .S_AXI_AWREADY(M_AXI_AWREADY),
        .S_AXI_WDATA(M_AXI_WDATA),
        .S_AXI_WSTRB(M_AXI_WSTRB),
        .S_AXI_WLAST(M_AXI_WLAST),
        .S_AXI_WUSER(M_AXI_WUSER),
        .S_AXI_WVALID(M_AXI_WVALID),
        .S_AXI_WREADY(M_AXI_WREADY),
        .S_AXI_BID(M_AXI_BID),
        .S_AXI_BRESP(M_AXI_BRESP),
        .S_AXI_BUSER(M_AXI_BUSER),
        .S_AXI_BVALID(M_AXI_BVALID),
        .S_AXI_BREADY(M_AXI_BREADY),
        .S_AXI_ARID(M_AXI_ARID),
        .S_AXI_ARADDR(M_AXI_ARADDR),
        .S_AXI_ARLEN(M_AXI_ARLEN),
        .S_AXI_ARSIZE(M_AXI_ARSIZE),
        .S_AXI_ARBURST(M_AXI_ARBURST),
        .S_AXI_ARLOCK(M_AXI_ARLOCK),
        .S_AXI_ARCACHE(M_AXI_ARCACHE),
        .S_AXI_ARPROT(M_AXI_ARPROT),
        .S_AXI_ARQOS(M_AXI_ARQOS),
        .S_AXI_ARUSER(M_AXI_ARUSER),
        .S_AXI_ARVALID(M_AXI_ARVALID),
        .S_AXI_ARREADY(M_AXI_ARREADY),
        .S_AXI_RID(M_AXI_RID),
        .S_AXI_RDATA(M_AXI_RDATA),
        .S_AXI_RRESP(M_AXI_RRESP),
        .S_AXI_RLAST(M_AXI_RLAST),
        .S_AXI_RUSER(M_AXI_RUSER),
        .S_AXI_RVALID(M_AXI_RVALID),
        .S_AXI_RREADY(M_AXI_RREADY)
    );

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年10月27日 05:00 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBOにHDLで書いたラプラシアンフィルタを実装する3(FIFO の生成3)

ZYBOにHDLで書いたラプラシアンフィルタを実装する2(FIFO の生成2)”の続き。

前回まででは、Write用のFIFO を生成したので、今回はRead用のFIFO を生成する。

最初に、read_adfifo を生成する。

Coregen を立ち上げて read_adfifo の設定を見た。
lap_fil_HDL_axim_27_151025.png

Vivado 2015.3 の read_adfifo の FIFO Generator の画面を示す。
lap_fil_HDL_axim_28_151025.png

Native Ports タブ
lap_fil_HDL_axim_29_151025.png

Status Flags タブ
lap_fil_HDL_axim_30_151025.png

Data Counts タブ
lap_fil_HDL_axim_31_151025.png

Summary タブ
lap_fil_HDL_axim_32_151025.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。
Generate ボタンをクリックした。
ダイアログが表示されたので、OKボタンをクリックした。
これで、read_adfifo の生成が終了した。

次は、read_adfifo_outs を生成する。

Coregen を立ち上げて read_adfifo_outs の設定を見た。
lap_fil_HDL_axim_33_151025.png

Vivado 2015.3 の read_adfifo_outs の FIFO Generator の画面を示す。
lap_fil_HDL_axim_34_151025.png

Native Ports タブ
lap_fil_HDL_axim_35_151025.png

Status Flags タブ
lap_fil_HDL_axim_36_151025.png

Data Counts タブ
lap_fil_HDL_axim_37_151025.png

Summary タブ
lap_fil_HDL_axim_38_151025.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。
Generate ボタンをクリックした。
ダイアログが表示されたので、OKボタンをクリックした。
これで、read_adfifo_outs の生成が終了した。

最後は、read_fifo を生成する。

Coregen を立ち上げて read_fifo の設定を見た。
lap_fil_HDL_axim_39_151025.png

Vivado 2015.3 の read_fifo の FIFO Generator の画面を示す。
lap_fil_HDL_axim_40_151025.png

Native Ports タブ
lap_fil_HDL_axim_41_151025.png

Status Flags タブ
lap_fil_HDL_axim_42_151025.png

Data Counts タブ
lap_fil_HDL_axim_43_151025.png

Summary タブ
lap_fil_HDL_axim_44_151025.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。
Generate ボタンをクリックした。
ダイアログが表示されたので、OKボタンをクリックした。
read_fifo の生成が終了した。

これで、すべてのFIFOが生成された。Vivado 2015.3 のプロジェクトを示す。
lap_fil_HDL_axim_45_151025.png

試しに合成してみたが、成功した。
lap_fil_HDL_axim_46_151025.png
合成結果は削除した。

すべてのFIFO の設定表を示す。
lap_fil_HDL_axim_47_151025.png
  1. 2015年10月26日 04:01 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

ZYBOにHDLで書いたラプラシアンフィルタを実装する2(FIFO の生成2)

ZYBOにHDLで書いたラプラシアンフィルタを実装する1(FIFO の生成1)”の続き。

前回は、write_adfifo の生成を行ったが、今回はその続きで、Write関連のFIFOの生成を行う。

最初に write_adfifo_outs の生成を行う。

Coregen を立ち上げて write_adfifo_outs の設定を見た。
lap_fil_HDL_axim_12_151025.png

Vivado 2015.3 の write_adfifo_outs の FIFO Generator の画面を示す。
lap_fil_HDL_axim_13_151025.png

Native Ports タブ
lap_fil_HDL_axim_14_151025.png

Status Flags タブ
lap_fil_HDL_axim_15_151025.png

Data Counts タブ
lap_fil_HDL_axim_16_151025.png

Summary タブ
lap_fil_HDL_axim_17_151025.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。
lap_fil_HDL_axim_18_151025.png

Generate ボタンをクリックした。

ダイアログが表示されたので、OKボタンをクリックした。
lap_fil_HDL_axim_19_151025.png

これで、write_adfifo_outs の生成が終了した。
lap_fil_HDL_axim_20_151025.png

次に、write_fifo の生成を行う。

Coregen を立ち上げて write_fifo の設定を見た。
lap_fil_HDL_axim_21_151025.png

Vivado 2015.3 の write_fifo の FIFO Generator の画面を示す。
lap_fil_HDL_axim_22_151025.png

Native Ports タブ
lap_fil_HDL_axim_23_151025.png

Status Flags タブ
lap_fil_HDL_axim_24_151025.png

Data Counts タブ
lap_fil_HDL_axim_25_151025.png

Summary タブ
lap_fil_HDL_axim_26_151025.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。

Generate ボタンをクリックした。

ダイアログが表示されたので、OKボタンをクリックした。

これで、write_fifo の生成が終了した。

Write関連のFIFOの生成は終了した。
  1. 2015年10月25日 09:01 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Atlas-SoC のÅngström Distribution にOpenCV をインストールする

Atlas-SoC のÅngström Distribution にOpenCV をインストールした。

最初に参考させて頂いたサイトを紹介する。”Intel Edison + OpenCVで顔認識”だ。

そのサイトに従って、opencv をインストールした。

最初は、update と upgrade を行った。

opkg update
opkg upgrade


次に opkg で opencv をインストールした。

opkg install opencv

DE0-Nano-SoC_44_151022.png

次に python-opencv をインストールした。

opkg install python-opencv

DE0-Nano-SoC_45_151022.png

python-opencv のインストールが終了した。
DE0-Nano-SoC_46_151022.png

haarcascade_frontalface_alt.xml のダウンロードだが、”Intel Edison + OpenCVで顔認識”に書いてあるサイトから wget しても無いと言われてしまう。
そこで、VNCを立ちあげて、Atlas-SoC に接続して、そこの Midori ブラウザからダウンロードすることにした。URLを示す。

http://sourceforge.net/projects/roboticscode/files/Face%20Tracker/haarcascade_frontalface_alt.xml/download?use_mirror=jaist&r=http%3A%2F%2Fosdn.jp%2Fprojects%2Fsfnet_roboticscode%2Fdownloads%2FFace%2520Tracker%2Fhaarcascade_frontalface_alt.xml%2F&use_mirror=jaist

DE0-Nano-SoC_47_151024.png

Save As ボタンをクリックして、/home/root/ にセーブした。
DE0-Nano-SoC_48_151024.png

次は、サンプルのレナ像をダウンロードする。下のURLからレナ像をダウンロードさせて頂いた。

http://www.eml.ele.cst.nihon-u.ac.jp/~momma/wiki/wiki.cgi/RSJ2011.html

DE0-Nano-SoC_49_151024.png
レナ像の所で、右クリックメニューから、Save Image As を選択した。

ダイアログが出てくるので、Save As ボタンをクリックした。
DE0-Nano-SoC_50_151024.png

/home/root/ に lena.jpg という名前でセーブした。
DE0-Nano-SoC_51_151024.png

確かにセーブ出来ている。
DE0-Nano-SoC_52_151024.png

次に、顔検出をするソフトウェアを用意する必要がある。これは、”python+OpenCVで顔認識をやってみる”の recognize.py を使わせて頂いた。
Midori で”python+OpenCVで顔認識をやってみる”を表示して、gedit を立ちあげて、Python コードをコピー・アンド・ペーストした。
更に、cascade_path を変更した。日本語がトーフになっているが気にしない。。。
DE0-Nano-SoC_53_151024.png

recognize.py をセーブした。
DE0-Nano-SoC_54_151024.png

VNC 上で Terminal を立ちあげて、

python recognize.py

を実行した。
DE0-Nano-SoC_55_151024.png
すると、detected.jpg が生成された。

detected.jpga を表示すると、レナ像の顔が検出されていた。
DE0-Nano-SoC_56_151024.png

GIMPが入っているので、GIMPで画像を表示しているが、起動が重い。。。
  1. 2015年10月24日 07:36 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:2

ZYBOにHDLで書いたラプラシアンフィルタを実装する1(FIFO の生成1)

以前、ZedBoard 用にHDLで書いたラプラシアンフィルタのIP があった。(”AXI4 Master アクセスのラプラシアン・フィルタ IP9(できた。完成)”)
これをZYBO用にVivado 2015.3 で再度実装してみたいと思う。

ZYBO 用のVivado のプロジェクトにしたのだが、Coregen でつくってあるFIFOは読み込めない。
そこでFIFO Generator で作り直すことにした。
lap_fil_HDL_axim_1_151023.png

FIFO は汎用AXI Master IP の所に使われているので、”AXI4 Master Interfaceモジュールの作製2(シミュレーション)”のISE プロジェクトを立ちあげてFIFO の設定を真似て、Vivado の FIFO Generator で設定を入れることにした。
lap_fil_HDL_axim_2_151023.png

ISEを立ち上げるのは久しぶりだ。懐かしい。。。

Coregen を立ち上げて write_adfifo の設定を見た。
lap_fil_HDL_axim_3_151023.png

Vivado 2015.3 の write_adfifo の FIFO Generator の画面を示す。
lap_fil_HDL_axim_4_151023.png

Native Ports タブ
lap_fil_HDL_axim_5_151023.png

Status Flags タブ
lap_fil_HDL_axim_6_151023.png

Data Counts タブ
lap_fil_HDL_axim_7_151023.png

Summary タブ
lap_fil_HDL_axim_8_151023.png

OK ボタンをクリックすると、Generate Output Products ダイアログが表示された。
lap_fil_HDL_axim_9_151023.png

Generate ボタンをクリックした。

ダイアログが表示されたので、OKボタンをクリックした。
lap_fil_HDL_axim_10_151023.png

これで、write_adfifo の生成が終了した。
lap_fil_HDL_axim_11_151023.png
  1. 2015年10月23日 05:08 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

”Atlas-SoC素晴らしいんじゃないの”をやってみる3

”Atlas-SoC素晴らしいんじゃないの”をやってみる2”の続き。

Atlas-SoC のイメージを Micro SD カードのWrite して、DE0-Nano-SoC ボードに挿入した。USBをLAN接続するドライバをインストールし、Web ページを表示している。

今回は、Try -> Developing on the Atlas-SoC Board (via SSH or VNC) の VNC をインストールしてみた。
そのページのVNC の Download ボタンをクリックしてTightVNC をダウンロードした。
DE0-Nano-SoC_24_151020.png

TightVNC のWindows 64 ビット版をダウンロードして、インストールした。

TightVNC Viewer を立ちあげて、Remote Host に 192.168.7.1 を指定して Connect した。
DE0-Nano-SoC_25_151020.png

すると、DE0-Nano-SoC ボードで起動しているLinux のディスクトップが見えた。
DE0-Nano-SoC_26_151020.png

Web ブラウザ(Midori)も起動できるし、File Manager も起動することができた。
但し、Midori は日本語フォントが入っていなかった。
DE0-Nano-SoC_27_151020.png

これで、大体、”Atlas-SoC素晴らしいんじゃないの”の内容は終了だ。
  1. 2015年10月21日 04:26 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:0

Atlas-SoC のMicro SD カードのÅngström Distribution について

Atlas-SoC のMicro SD カードでLinux をブートした時のブートメッセージ”を見ると、Atlas-SoC のMicro SD カードのLinux Distribution はÅngström Distribution の様だ。

YOCTO PROJECT COMPATIBLE, 1.7 THIS TIME ということなので、Yocto コンパチのLinux のようだ。

BeagleBoard-xMでAngstrom Linuxを動かす”によると、Angstromのオンラインビルダー・ページがあって、Webページ上で設定していくことによってLinux のシステムイメージをビルドできるということだが、今はWebページが無くなっているようだ。

opkg update
opkg upgrade

をやってみた。(VNC の環境がすでに走っている)
DE0-Nano-SoC_29_151021.png

真ん中のターミナルで opkg upgrade を実行中だ。
終了したらVNC Viewer が落ちてしまった。
シリアルから reboot して、もう一度、VNC Viewer を立ちあげて、DE0-Nano-SoC ボードに接続した。

BeagleBoard-xMでAngstrom Linuxを動かす”を参考にタイムゾーンを UTC から JST に変更した(2015/10/23:追記 JSTに変更するとVNC Viewer で接続した時にネットに繋がらない気がするので、UTCのままの方が良さそうだ)

cd /etc
mv localtime localtime.orig
ln -s /usr/share/zoneinfo/Asia/Tokyo localtime

DE0-Nano-SoC_30_151021.png
  1. 2015年10月21日 04:05 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:0

Atlas-SoC のMicro SD カードでLinux をブートした時のブートメッセージ

Atlas-SoC のMicro SD カードでLinux をブートした時のブートメッセージが取得できたので、貼っておく。

0
reading u-boot.scr
903 bytes read in 6 ms (146.5 KiB/s)
## Executing script at 02000000
---Booting ATLAS SOC GHRD---
---Programming FPGA---
reading ATLAS_SOC_GHRD/output_files/ATLAS_SOC_GHRD.rbf
2109256 bytes read in 152 ms (13.2 MiB/s)
---Setting Env variables---
## Starting application at 0x3FF79550 ...
## Application terminated, rc = 0x0
---Generating MAC Address---
ethaddr = 00:07:ed:40:66:10
---Booting Linux---
reading zImage
3975760 bytes read in 269 ms (14.1 MiB/s)
reading zImage-socfpga_cyclone5_de0_sockit.dtb
22711 bytes read in 11 ms (2 MiB/s)
## Flattened Device Tree blob at 00000100
   Booting using the fdt blob at 0x00000100
   reserving fdt memory region: addr=0 size=1000
   Loading Device Tree to 03ff7000, end 03fff8b6 ... OK

Starting kernel ...

Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 4.0.0-altera (dwesterg@sj-dwesterg2-ll) (gcc version 4.9.3 20141031 (prerelease) (Linaro GCC 4.9-2014.11) ) #1 SMP Mon Oct 5 07:51:48 PDT 2015
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Terasic DE-0(Atlas)
Memory policy: Data cache writealloc
PERCPU: Embedded 11 pages/cpu @bf7cc000 s15424 r8192 d21440 u45056
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 260096
Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 1030632K/1048576K available (6028K kernel code, 254K rwdata, 1792K rodata, 432K init, 197K bss, 17944K reserved, 0K cma-reserved)
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
    vmalloc : 0xc0800000 - 0xff000000   (1000 MB)
    lowmem  : 0x80000000 - 0xc0000000   (1024 MB)
    modules : 0x7f000000 - 0x80000000   (  16 MB)
      .text : 0x80008000 - 0x807ab448   (7822 kB)
      .init : 0x807ac000 - 0x80818000   ( 432 kB)
      .data : 0x80818000 - 0x808579d0   ( 255 kB)
       .bss : 0x808579d0 - 0x808890a4   ( 198 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
Hierarchical RCU implementation.
        Additional per-CPU info printed with stalls.
        RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
NR_IRQS:16 nr_irqs:16 16
L2C: platform modifies aux control register: 0x02060000 -> 0x32460000
L2C: platform provided aux values permit register corruption.
L2C: DT/platform modifies aux control register: 0x02060000 -> 0x32460000
L2C-310 erratum 769419 enabled
L2C-310 enabling early BRESP for Cortex-A9
L2C-310 full line of zeros enabled for Cortex-A9
L2C-310 ID prefetch enabled, offset 1 lines
L2C-310 dynamic clock gating enabled, standby mode enabled
L2C-310 cache controller enabled, 8 ways, 512 kB
L2C-310: CACHE_ID 0x410030c9, AUX_CTRL 0x76460001
sched_clock: 32 bits at 100MHz, resolution 10ns, wraps every 42949672950ns
Console: colour dummy device 80x30
Calibrating delay loop... 1836.64 BogoMIPS (lpj=9183232)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
CPU: Testing write buffer coherency: ok
ftrace: allocating 20063 entries in 59 pages
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x572258 - 0x5722b0
CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
Brought up 2 CPUs
SMP: Total of 2 processors activated (3679.84 BogoMIPS).
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
NET: Registered protocol family 16
fpga bridge driver
DMA: preallocated 256 KiB pool for atomic coherent allocations
hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
hw-breakpoint: maximum watchpoint size is 4 bytes.
altera_hps2fpga_bridge soc:fpgabridge@0: fpga bridge [hps2fpga] registered as device hps2fpga
altera_hps2fpga_bridge soc:fpgabridge@0: init-val not specified
altera_hps2fpga_bridge soc:fpgabridge@1: fpga bridge [lwhps2fpga] registered as device lwhps2fpga
altera_hps2fpga_bridge soc:fpgabridge@1: init-val not specified
altera_hps2fpga_bridge soc:fpgabridge@2: fpga bridge [fpga2hps] registered as device fpga2hps
altera_hps2fpga_bridge soc:fpgabridge@2: init-val not specified
FPGA Mangager framework driver
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
PTP clock support registered
Switched to clocksource timer1
NET: Registered protocol family 2
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP: reno registered
UDP hash table entries: 512 (order: 2, 16384 bytes)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
hw perfevents: enabled with armv7_cortex_a9 PMU driver, 7 counters available
arm-pmu arm-pmu: PMU:CTI successfully enabled for 2 cores
futex hash table entries: 512 (order: 3, 32768 bytes)
audit: initializing netlink subsys (disabled)
audit: type=2000 audit(0.210:1): initialized
NFS: Registering the id_resolver key type
Key type id_resolver registered
Key type id_legacy registered
ntfs: driver 2.1.31 [Flags: R/W].
jffs2: version 2.2. (NAND) (SUMMARY)  c 2001-2006 Red Hat, Inc.
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 250)
io scheduler noop registered (default)
io scheduler deadline registered
io scheduler cfq registered
Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
console [ttyS0] disabled
ffc02000.serial0: ttyS0 at MMIO 0xffc02000 (irq = 42, base_baud = 6250000) is a 16550A
console [ttyS0] enabled
ffc03000.serial1: ttyS1 at MMIO 0xffc03000 (irq = 43, base_baud = 6250000) is a 16550A
altera_fpga_manager ff706000.fpgamgr: fpga manager [Altera FPGA Manager] registered as minor 0
brd: module loaded
loop: module loaded
libphy: Fixed MDIO Bus: probed
CAN device driver interface
stmmac - user ID: 0x10, Synopsys ID: 0x37
 Ring mode enabled
 DMA HW capability register supported
 Enhanced/Alternate descriptors
        Enabled extended descriptors
 RX Checksum Offload Engine supported (type 2)
 TX Checksum insertion supported
 Enable RX Mitigation via HW Watchdog Timer
libphy: stmmac: probed
eth0: PHY ID 00221622 at 1 IRQ POLL (stmmac-0:01) active
dwc2 ffb40000.usb: EPs: 16, dedicated fifos, 8064 entries in SPRAM
dwc2 ffb40000.usb: DWC OTG Controller
dwc2 ffb40000.usb: new USB bus registered, assigned bus number 1
dwc2 ffb40000.usb: irq 44, io mem 0x00000000
usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: DWC OTG Controller
usb usb1: Manufacturer: Linux 4.0.0-altera dwc2_hsotg
usb usb1: SerialNumber: ffb40000.usb
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver usb-storage
mousedev: PS/2 mouse device common for all mice
input: ADXL34x accelerometer as /devices/platform/soc/ffc04000.i2c/i2c-0/0-0053/input/input0
i2c /dev entries driver
Driver 'mmcblk' needs updating - please use bus_type methods
Synopsys Designware Multimedia Card Interface Driver
dw_mmc ff704000.dwmmc0: IDMAC supports 32-bit address mode.
dw_mmc ff704000.dwmmc0: Using internal DMA controller.
dw_mmc ff704000.dwmmc0: Version ID is 240a
dw_mmc ff704000.dwmmc0: DW MMC controller at irq 32, 32 bit host data width, 1024 deep fifo
dw_mmc ff704000.dwmmc0: No vmmc regulator found
dw_mmc ff704000.dwmmc0: No vqmmc regulator found
dw_mmc ff704000.dwmmc0: 1 slots initialized
platform soc:leds: Driver leds-gpio requests probe deferral
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
oprofile: using arm/armv7-ca9
TCP: cubic registered
NET: Registered protocol family 10
sit: IPv6 over IPv4 tunneling driver
NET: Registered protocol family 17
NET: Registered protocol family 15
can: controller area network core (rev 20120528 abi 9)
NET: Registered protocol family 29
can: raw protocol (rev 20120528)
can: broadcast manager protocol (rev 20120528 t)
can: netlink gateway (rev 20130117) max_hops=1
8021q: 802.1Q VLAN Support v1.8
Key type dns_resolver registered
ThumbEE CPU extension supported.
Registering SWP/SWPB emulation handler
platform soc:leds: Driver leds-gpio requests probe deferral
platform soc:keys: Driver gpio-keys requests probe deferral
mmc_host mmc0: Bus speed (slot 0) = 50000000Hz (slot req 50000000Hz, actual 50000000HZ div = 0)
mmc0: new high speed SDHC card at address 0007
mmcblk0: mmc0:0007 SD8GB 7.42 GiB
 mmcblk0: p1 p2 p3
platform soc:leds: Driver leds-gpio requests probe deferral
/data/atlas-soc/17-master/setup-scripts/build/tmp-angstrom_v2014_12-glibc/work/atlas_sockit-angstrom-linux-gnueabi/linux-altera/4.0+gitAUTOINC+5d36469775-r15/linux/drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
platform soc:leds: Driver leds-gpio requests probe deferral
platform soc:keys: Driver gpio-keys requests probe deferral
ttyS0 - failed to request DMA
random: nonblocking pool is initialized
kjournald starting.  Commit interval 5 seconds
EXT3-fs (mmcblk0p2): using internal journal
EXT3-fs (mmcblk0p2): recovery complete
EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
VFS: Mounted root (ext3 filesystem) on device 179:2.
devtmpfs: mounted
Freeing unused kernel memory: 432K (807ac000 - 80818000)
systemd[1]: Failed to insert module 'autofs4'
systemd[1]: systemd 219 running in system mode. (+PAM -AUDIT -SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP -LIBCRYPTSETUP -GCRYPT -GNUTLS +ACL +XZ -LZ4 -SECCOMP +BLKID -ELFUTILS +KMOD +IDN)
systemd[1]: Detected architecture arm.

Welcome to The Angstrom Distribution v2014.12!

systemd[1]: Set hostname to <atlas_sockit>.
systemd-sysv-generator[679]: Overwriting existing symlink /run/systemd/generator.late/fuse.service with real service
systemd-sysv-generator[679]: Overwriting existing symlink /run/systemd/generator.late/gator.service with real service
systemd[1]: Cannot add dependency job for unit org.freedesktop.resolve1.busname, ignoring: Unit org.freedesktop.resolve1.busname failed to load: No such file or directory.
systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
systemd[1]: Starting Dispatch Password Requests to Console Directory Watch.
[  OK  ] Reached target Swap.
systemd[1]: Reached target Swap.
systemd[1]: Starting Swap.
systemd[1]: Started Forward Password Requests to Wall Directory Watch.
systemd[1]: Starting Forward Password Requests to Wall Directory Watch.
[  OK  ] Reached target Paths.
systemd[1]: Reached target Paths.
systemd[1]: Starting Paths.
[  OK  ] Created slice Root Slice.
systemd[1]: Created slice Root Slice.
systemd[1]: Starting Root Slice.
[  OK  ] Listening on Journal Socket (/dev/log).
systemd[1]: Listening on Journal Socket (/dev/log).
systemd[1]: Starting Journal Socket (/dev/log).
[  OK  ] Listening on Syslog Socket.
systemd[1]: Listening on Syslog Socket.
systemd[1]: Starting Syslog Socket.
[  OK  ] Created slice System Slice.
systemd[1]: Created slice System Slice.
systemd[1]: Starting System Slice.
[  OK  ] Created slice system-getty.slice.
systemd[1]: Created slice system-getty.slice.
systemd[1]: Starting system-getty.slice.
[  OK  ] Created slice system-serial\x2dgetty.slice.
systemd[1]: Created slice system-serial\x2dgetty.slice.
systemd[1]: Starting system-serial\x2dgetty.slice.
[  OK  ] Listening on Journal Audit Socket.
systemd[1]: Listening on Journal Audit Socket.
systemd[1]: Starting Journal Audit Socket.
[  OK  ] Listening on udev Control Socket.
systemd[1]: Listening on udev Control Socket.
systemd[1]: Starting udev Control Socket.
[  OK  ] Listening on Journal Socket.
systemd[1]: Listening on Journal Socket.
systemd[1]: Starting Journal Socket.
systemd[1]: Starting Journal Service...
         Starting Journal Service...
systemd[1]: Started Bind mount volatile /var/lib.
systemd[1]: Mounting Debug File System...
         Mounting Debug File System...
systemd[1]: Started File System Check on Root Device.
systemd[1]: Starting Remount Root and Kernel File Systems...
         Starting Remount Root and Kernel File Systems...
[  OK  ] Listening on networkd rtnetlink socket.
systemd[1]: Listening on networkd rtnetlink socket.
systemd[1]: Starting networkd rtnetlink socket.
[  OK  ] Listening on /dev/initctl Compatibility Named Pipe.
systemd[1]: Listening on /dev/initctl Compatibility Named Pipe.
systemd[1]: Starting /dev/initctl Compatibility Named Pipe.
[  OK  ] Created slice User and Session Slice.
systemd[1]: Created slice User and Session Slice.
systemd[1]: Starting User and Session Slice.
[  OK  ] Reached target Slices.
systemd[1]: Reached target Slices.
systemd[1]: Starting Slices.
systemd[1]: Mounted Huge Pages File System.
[  OK  ] Listening on udev Kernel Socket.
systemd[1]: Listening on udev Kernel Socket.
systemd[1]: Starting udev Kernel Socket.
systemd[1]: Starting udev Coldplug all Devices...
         Starting udev Coldplug all Devices...
[  OK  ] Listening on Delayed Shutdown Socket.
systemd[1]: Listening on Delayed Shutdown Socket.
systemd[1]: Starting Delayed Shutdown Socket.
systemd[1]: Started Load Kernel Modules.
systemd[1]: Mounting Configuration File System...
         Mounting Configuration File System...
systemd[1]: Mounted FUSE Control File System.
systemd[1]: Starting Apply Kernel Variables...
         Starting Apply Kernel Variables...
systemd[1]: Mounted POSIX Message Queue File System.
systemd[1]: Starting Create list of required static device nodes for the current kernel...
         Starting Create list of required st... nodes for the current kernel...
[  OK  ] Mounted Debug File System.
systemd[1]: Mounted Debug File System.
[  OK  ] Mounted Configuration File System.
systemd[1]: Mounted Configuration File System.
[  OK  ] Started Remount Root and Kernel File Systems.
systemd[1]: Started Remount Root and Kernel File Systems.
[  OK  ] Started Apply Kernel Variables.
systemd[1]: Started Apply Kernel Variables.
[  OK  ] Started Create list of required sta...ce nodes for the current kernel.
systemd[1]: Started Create list of required static device nodes for the current kernel.
[  OK  ] Started udev Coldplug all Devices.
systemd[1]: Started udev Coldplug all Devices.
[  OK  ] Started Journal Service.
systemd[1]: Started Journal Service.
         Starting Load/Save Random Seed...
         Starting Create Static Device Nodes in /dev...
         Starting Flush Journal to Persistent Storage...
[  OK  ] Started Load/Save Random Seed.
systemd-journald[686]: Received request to flush runtime journal from PID 1
[  OK  ] Started Create Static Device Nodes in /dev.
         Starting udev Kernel Device Manager...
[  OK  ] Reached target Local File Systems (Pre).
         Mounting /tmp...
[  OK  ] Mounted /tmp.
[  OK  ] Reached target Local File Systems.
[  OK  ] Started Flush Journal to Persistent Storage.
         Starting Create Volatile Files and Directories...
[  OK  ] Started Create Volatile Files and Directories.
         Starting Network Time Synchronization...
         Starting Update UTMP about System Boot/Shutdown...
[  OK  ] Started udev Kernel Device Manager.
[  OK  ] Started Network Time Synchronization.
[  OK  ] Reached target System Time Synchronized.
[  OK  ] Started Update UTMP about System Boot/Shutdown.
platform soc:leds: Driver leds-gpio requests probe deferral
platform soc:keys: Driver gpio-keys requests probe deferral
[  OK  ] Found device /dev/ttyS0.
platform soc:leds: Driver leds-gpio requests probe deferral
platform soc:keys: Driver gpio-keys requests probe deferral
[  OK  ] Reached target System Initialization.
ff202000.serial: ttyJ0 at MMIO 0xff202000 (irq = 46, base_baud = 0) is a Altera JTAG UART
input: soc:keys as /devices/platform/soc/soc:keys/input/input1
[  OK  ] Listening on RPCbind Server Activation Socket.
         Starting Console System Startup Logging...
[  OK  ] Listening on Avahi mDNS/DNS-SD Stack Activation Socket.
[  OK  ] Listening on D-Bus System Message Bus Socket.
[  OK  ] Reached target Timers.
[  OK  ] Started Console System Startup Logging.
[  OK  ] Listening on sshd.socket.
[  OK  ] Reached target Sockets.
[  OK  ] Reached target Basic System.
[  OK  ] Started Atlas X11VNC server.
         Starting Atlas X11VNC server...
[  OK  ] Started Timestamping service.
         Starting Timestamping service...
         Starting LSB: Starts gatord...
[  OK  ] Started Start usb mass storage gadget.
         Starting Start usb mass storage gadget...
         Starting Avahi mDNS/DNS-SD Stack...
[  OK  ] Started System Logging Service.
         Starting System Logging Service...
[  OK  ] Started Periodic Command Scheduler.
         Starting Periodic Command Scheduler...
using random self ethernet address
using random host ethernet address
         Starting Connection service...
[  OK  ] Started Atlas SoC fftsw init.
Number of LUNs=8
Mass Storage Function, version: 2009/09/11
LUN: removable file: (no medium)
Number of LUNs=1
LUN: file: /usr/share/atlas-soc-usb-gadget/fat_image.img
Number of LUNs=1
usb0: HOST MAC 5e:2e:5a:42:93:28
usb0: MAC 4a:f9:21:8a:b6:22
g_multi gadget: Multifunction Composite Gadget
g_multi gadget: userspace failed to provide iSerialNumber
g_multi gadget: g_multi ready
dwc2 ffb40000.usb: bound driver g_multi
         Starting Atlas SoC fftsw init...
         Starting Network Time Service (one-shot ntpdate mode)...
[  OK  ] Started D-Bus System Message Bus.
gator: perf pmu: armv7_cortex_a9
gator: Adding cpu counters for ARMv7_Cortex_A9 with type 6
dwc2 ffb40000.usb: new device is high-speed
[  OK  ] Started Avahi mDNS/DNS-SD Stack.
         Starting D-Bus System Message Bus...
         Starting Network Service...
         Starting Login Service...
[  OK  ] Started Kernel Logging Service.
         Starting Kernel Logging Service...
[  OK  ] Started LSB: Starts gatord.
dwc2 ffb40000.usb: new device is high-speed
[  OK  ] Started Network Time Service (one-shot ntpdate mode).
[  OK  ] Started Network Service.
[  OK  ] Found device /dev/ttyGS0.
dwc2 ffb40000.usb: new address 1
[  OK  ] Started Connection service.
[  OK  ] Started Login Service.
g_multi gadget: high-speed config #1: Multifunction with RNDIS
[  OK  ] Reached target Remote File Systems.
         Starting Permit User Sessions...
[  OK  ] Reached target Network.
         Starting Samba NMB Daemon...
         Starting Lightning Fast Webserver With Light System Requirements...
         Starting Network Name Resolution...
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
[  OK  ] Started Permit User Sessions.
[  OK  ] Started Serial Getty on ttyS0.
         Starting Serial Getty on ttyS0...
[  OK  ] Started Serial Getty on ttyGS0.
         Starting Serial Getty on ttyGS0...
[  OK  ] Started Getty on tty1.
         Starting Getty on tty1...
[  OK  ] Reached target Login Prompts.
[  OK  ] Started Network Name Resolution.
[  OK  ] Started Lightning Fast Webserver With Light System Requirements.
         Starting WPA supplicant...
[  OK  ] Started Samba NMB Daemon.
         Starting Samba SMB Daemon...
[  OK  ] Started WPA supplicant.
[  OK  ] Started Samba SMB Daemon.
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
[  OK  ] Reached target Multi-User System.
         Starting Update UTMP about System Runlevel Changes...
[  OK  ] Started Update UTMP about System Runlevel Changes.
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)
IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready

.---O---.
|       |                  .-.           o o
|   |   |-----.-----.-----.| |   .----..-----.-----.
|       |     | __  |  ---'| '--.|  .-'|     |     |
|   |   |  |  |     |---  ||  --'|  |  |  '  | | | |
'---'---'--'--'--.  |-----''----''--'  '-----'-'-'-'
                -'  |
                '---'

The Angstrom Distribution atlas_sockit ttyS0

Angstrom v2014.12 - Kernel 4.0.0-altera

atlas_sockit login: stmmaceth ff702000.ethernet eth0: Link is Up - 100Mbps/Full - flow control off
IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 1)
dwc2 ffb40000.usb: s3c_hsotg_start_req: ep5 is stalled
dwc2 ffb40000.usb: s3c_hsotg_ep_sethalt(ep be9c5690 ep5in, 0)


アスキーアートが潰れているので、下に貼っておく。
DE0-Nano-SoC_28_151021.png
  1. 2015年10月21日 03:37 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:0

”Atlas-SoC素晴らしいんじゃないの”をやってみる2

”Atlas-SoC素晴らしいんじゃないの”をやってみる1”の続き。

前回、Atlas-SoC のイメージを Micro SD カードのWrite して、USBをLAN接続するドライバをインストールし、Web ページを表示するところまでできた。

今回は、”Atlas-SoC素晴らしいんじゃないの”を参考に、そのWeb ページを堪能してみたい。

この画面はPlay をクリックしたところだ。Blink The LEDs をクリックした。
DE0-Nano-SoC_19_151020.png

Blink The LEDs が表示された。
DE0-Nano-SoC_20_151020.png

All On をクリックすると、8個あるLED のうちの一番左のLEDだけが点灯し、順番に右に点灯していく。見ているフラッシャーのようだ。
All Off は一番右のLED が消灯して、順次左のLED が消灯していく。
Blink は一番右のLED が最初について、左のLED が点灯していき、全部のLED が点灯したら、右のLED から消灯していく。フラッシャーのように見える。

Accelerometer はどうやるのか、よくわからなかった。

Fast Fourier Transform をやってみた。

FFTはSine Wave でやってみた。
DE0-Nano-SoC_21_151020.png

Data Source in HPS と Data Source in FPGA の2つの方法でFFT をテストしているようだ。それぞれ、FFT の大きさごとに評価している。Data Source in HPS では、256 データでは、CPU の方が速いがそれ以外はFPGA でやったほうが速いという結果だ。

その下に、Data Source in HPS と Data Source in FPGA のブロック図がある。
最初にData Source in HPS を下に示す。
DE0-Nano-SoC_22_151020.png

CPU Procesing は925MHzのDual Core CPUで SDRAM 上のRAM Disk 上からソースデータをCPU が読んできて、NEON コプロセッサを使った計算ライブラリを使ってFFT して、またRAM Disk に書き込むそうだ。

FPGA Processing は100MHz動作のFFT コアを使用しているそうだ。
FPGAを使ったFFT では、RAM Disk の内容をFFT 上のDMA がACP ポートを使用してRead し、FPGA上のFFT エンジンがFFT を行って、やはりACP ポートを使って、RAM Disk に書き込むそうだ。

次は、Data Source in FPGA を下に示す。
DE0-Nano-SoC_23_151020.png

CPU Procesing は925MHzのDual Core CPUを使用している。
FPGA 上のDMA コアがACP ポートを経由してRAM Buffer のデータをCPU に送り、CPUがFFT を行う。たぶん、NEON コプロセッサを使っているんだろう?

FPGA Processing は同様に100MHz動作のFFT コアを使用しているそうだ。
FPGA 上のRAM Buffer のデータをDMA がFFT エンジンに送って、FFT を行い、別のDMA がACP ポートを通して、SDRAM に書き込むそうだ。

ブロック図まで付いていて、構造がわかりやすい。面白い。
  1. 2015年10月20日 04:17 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:2

”Atlas-SoC素晴らしいんじゃないの”をやってみる1

Atlas-SoC素晴らしいんじゃないの”をやってみたいということでやってみた。

まずは、手元にあるのは、DE0-Nano-SoC で Atlas-SoC じゃないので、Atlas-SoC のSDカード・イメージをダウンロードした。
RocketBoard.org に Atlas-SoC Development Platform があるが、その Getting Latest SD Card Image から atlas_sdcard_v1.1.img.tgz をダウンロードした。

この atlas_sdcard_v1.1.img.tgz を Lhaplus で解凍するときちんと解凍できなかったので、Cygwin を起動して、tar zxvf atlas_sdcard_v1.1.img.tgz で解凍することをお勧めする。(Windows 7 です)
そうすると atlas_sdcard_v1.1.img が解凍できた。
DE0-Nano-SoC_18_151019.png

新品の Class 10 の 8 GB Micro SD カード(4GBでも Class 4 でも良さそう)を SD Card Reader/Writer に入れて、パソコンに接続した。

まずは、SDFormatter でフォーマットしないと Win32 Disk Imager でイメージを書くことが出来なかった。
SDFormatter でフォーマットした。
DE0-Nano-SoC_4_151018.png

次に、Win32 Disk Imager を立ちあげて、atlas_sdcard_v1.1.img を選択した。
DE0-Nano-SoC_3_151018.png

Write ボタンをクリックして、イメージをMicro SD カードにWrite した。その際に、書き込むMicro SD カードかどうか必ずチェックすること。
イメージのWrite が始まった。
DE0-Nano-SoC_5_151018.png

イメージのWrite が終了すると、Windows に Micro SDカードのドライブが認識された。
DE0-Nano-SoC_6_151018.png

VirtualBox 上のUbuntu 14.04 にMicro SDカードをマウントすると、2つのドライブが見えた。やはり、Root File System がある。
DE0-Nano-SoC_7_151019.png

UART と USB OTG のUSBケーブルをパソコンに接続した。
FPGA Configuration Mode Switch (MSEL[4:0]) = 01010 (ON OFF ON OFF ON OFF)と設定した。
Micro SDカードを、DE0-Nano-SoC に入れて、電源ONした。

シリアルポートに Tera Term で接続すると、Linux が起動しているのが見えた。
DE0-Nano-SoC_8_151019.png

USB OTG の方は、パソコンがドライバを検索していたが、2つほど入らなかった。
DE0-Nano-SoC_9_151019.png

ドライバは2 つ入らなかったが、ドライブがマウントされた。
DE0-Nano-SoC_10_151019.png

フォルダを見ると、start.htm があるので、ダブルクリックした。
DE0-Nano-SoC_11_151019.png

すると start.htm が立ち上がった。
DE0-Nano-SoC_12_151019.png

ドライバをインストールしろと書いてあった。
G:\Drivers\Windows の下にある ATLAS_D64.exe をダブルクリックしてインストールした。(Windows 7 64 ビット版)
DE0-Nano-SoC_13_151019.png

デバイス・ドライバのインストールが始まった。
DE0-Nano-SoC_14_151019.png

途中で、Linux Developer Community ネットワーク アダプターをインストールするか聞いてくるので、インストールボタンをクリックする。
DE0-Nano-SoC_15_151019.png

デバイス・ドライバのインストールが終了した。
DE0-Nano-SoC_16_151019.png

192.168.7.1 を見ると、ATLAS-SoC のページが表示されていた。
DE0-Nano-SoC_17_151019.png

  1. 2015年10月19日 04:58 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:0

DE0-Nano-SoC をやってみる

Terasic の SoC FPGA(Xilinx で言えば Zynq)ボードの DE0-Nano-SoC が手に入ったので、やってみることにした。

電源用のACアダプタは 5V - 2A だった。

Micro SDカードが既に入っているので、FPGA Configuration Mode Switch (MSEL[4:0]) = 01010 (ON OFF ON OFF ON OFF)にして、UARTのUSB-mini BコネクタにUSBケーブルを接続してパソコンに接続した。

電源のACアダプタのプラグをDE0-Nano-SoC に接続した。(結構、基板が熱くなる。SoC FPGAを触ってみたがそんなに熱くないので、電源かな?かなり小さな基板なので放熱が厳しいのかもしれない?)

しばらく、パソコンで、UARTのドライバをインストールしていましたが、自動的にネットからドライバを取得できた。

UARTのドライバがインストールされたら、Tera Term を シリアル、115200bps, 8bit, 1 Stopbit に設定するとLinux が動作しているのが確認できた。
DE0-Nano-SoC_1_151018.png

Linux はYocto だった。

ls コマンドで、ファイルが見えたが、bt_test というファイルがあった。

ifconfig で見た。まだ LAN ケーブルは接続していない。LAN ケーブルを接続してもinet addr が表示されなかった。DHCPに対応させていないのか?

dmeg を実行した結果を示す。起動時のメッセージだ。

root@socfpga:~# dmesg
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 3.13.0-00298-g3c7cbb9-dirty (root@matthew) (gcc version 4.6.3 (Sourcery CodeBench Lite 2012.03-57) ) #8 SMP Wed Jan 7 10:48:09 CST 2015
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Altera SOCFPGA Cyclone V SoC Development Kit
cma: dma_contiguous_reserve(limit 40000000)
cma: dma_contiguous_reserve: reserving 512 MiB for global area
cma: dma_contiguous_reserve_area(size 20000000, base 00000000, limit 40000000)
cma: CMA: reserved 512 MiB at 20000000
Memory policy: Data cache writealloc
On node 0 totalpages: 262144
free_area_init_node: node 0, pgdat 80813340, node_mem_map 8085a000
Normal zone: 2048 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 262144 pages, LIFO batch:31
PERCPU: Embedded 8 pages/cpu @81067000 s11264 r8192 d13312 u32768
pcpu-alloc: s11264 r8192 d13312 u32768 alloc=8*4096
pcpu-alloc: [0] 0 [0] 1
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 260096
Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 505572K/1048576K available (6096K kernel code, 263K rwdata, 1512K rodata, 375K init, 261K bss, 543004K reserved)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0xc0800000 - 0xff000000 (1000 MB)
lowmem : 0x80000000 - 0xc0000000 (1024 MB)
modules : 0x7f000000 - 0x80000000 ( 16 MB)
.text : 0x80008000 - 0x80776570 (7610 kB)
.init : 0x80777000 - 0x807d4c00 ( 375 kB)
.data : 0x807d6000 - 0x80817ff8 ( 264 kB)
.bss : 0x80817ff8 - 0x80859434 ( 262 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:16 nr_irqs:16 16
sched_clock: 32 bits at 100MHz, resolution 10ns, wraps every 42949672950ns
Console: colour dummy device 80x30
Calibrating delay loop... 1836.64 BogoMIPS (lpj=9183232)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
ftrace: allocating 19140 entries in 57 pages
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x58a5b8 - 0x58a610
CPU1: Booted secondary processor
CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
Brought up 2 CPUs
SMP: Total of 2 processors activated.
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
NET: Registered protocol family 16
fpga bridge driver
cma: dma_alloc_from_contiguous(cma 8084c62c, count 64, align 6)
cma: dma_alloc_from_contiguous(): returned 80c5a000
DMA: preallocated 256 KiB pool for atomic coherent allocations
L310 cache controller enabled
l2x0: 8 ways, CACHE_ID 0x410030c9, AUX_CTRL 0x32460000, Cache size: 512 kB
syscon fffef000.l2-cache: regmap [mem 0xfffef000-0xfffeffff] registered
syscon ffd05000.rstmgr: regmap [mem 0xffd05000-0xffd05fff] registered
syscon ffc25000.sdrctl: regmap [mem 0xffc25000-0xffc25fff] registered
syscon ff800000.l3regs: regmap [mem 0xff800000-0xff800fff] registered
syscon ffd08000.sysmgr: regmap [mem 0xffd08000-0xffd0bfff] registered
hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
hw-breakpoint: maximum watchpoint size is 4 bytes.
altera_hps2fpga_bridge fpgabridge.2: fpga bridge [hps2fpga] registered as device hps2fpga
altera_hps2fpga_bridge fpgabridge.2: init-val not specified
altera_hps2fpga_bridge fpgabridge.3: fpga bridge [lshps2fpga] registered as device lwhps2fpga
altera_hps2fpga_bridge fpgabridge.3: init-val not specified
altera_hps2fpga_bridge fpgabridge.4: fpga bridge [fpga2hps] registered as device fpga2hps
altera_hps2fpga_bridge fpgabridge.4: init-val not specified
bio: create slab at 0
FPGA Mangager framework driver
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti
PTP clock support registered
Bluetooth: Core ver 2.17
NET: Registered protocol family 31
Bluetooth: HCI device and connection manager initialized
Bluetooth: HCI socket layer initialized
Bluetooth: L2CAP socket layer initialized
Bluetooth: SCO socket layer initialized
Switched to clocksource timer1
NET: Registered protocol family 2
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP: reno registered
UDP hash table entries: 512 (order: 2, 16384 bytes)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
arm-pmu arm-pmu: PMU:CTI successfully enabled for 2 cores
NFS: Registering the id_resolver key type
Key type id_resolver registered
Key type id_legacy registered
NTFS driver 2.1.30 [Flags: R/W].
jffs2: version 2.2. (NAND) \xffffffc2\xffffffa9 2001-2006 Red Hat, Inc.
msgmni has been set to 2011
io scheduler noop registered (default)
Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
ffc02000.serial0: ttyS0 at MMIO 0xffc02000 (irq = 194, base_baud = 6250000) is a 16550A
console [ttyS0] enabled
altera_fpga_manager ff706000.fpgamgr: fpga manager [Altera FPGA Manager] registered as minor 0
brd: module loaded
dw_spi_mmio fff01000.spi: master is unqueued, this is deprecated
CAN device driver interface
c_can_platform ffc00000.d_can: invalid resource
c_can_platform ffc00000.d_can: control memory is not used for raminit
c_can_platform ffc00000.d_can: c_can_platform device registered (regs=c089e000, irq=163)
stmmac - user ID: 0x10, Synopsys ID: 0x37
Ring mode enabled
DMA HW capability register supported
Enhanced/Alternate descriptors
Enabled extended descriptors
RX Checksum Offload Engine supported (type 2)
TX Checksum insertion supported
Enable RX Mitigation via HW Watchdog Timer
libphy: stmmac: probed
eth0: PHY ID 00221622 at 1 IRQ POLL (stmmac-0:01) active
dwc2 ffb40000.usb: unable to find phy
dwc2 ffb40000.usb: EPs:15
dwc2 ffb40000.usb: dedicated fifos
dwc2 ffb40000.usb: 2560 invalid for host_rx_fifo_size. Check HW configuration.
dwc2 ffb40000.usb: 2560 invalid for host_nperio_tx_fifo_size. Check HW configuration.
cma: dma_alloc_from_contiguous(cma 8084c62c, count 1, align 0)
cma: dma_alloc_from_contiguous(): returned 80c5a800
dwc2 ffb40000.usb: DWC OTG Controller
dwc2 ffb40000.usb: new USB bus registered, assigned bus number 1
dwc2 ffb40000.usb: irq 160, io mem 0x00000000
usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
usb usb1: Product: DWC OTG Controller
usb usb1: Manufacturer: Linux 3.13.0-00298-g3c7cbb9-dirty dwc2_hsotg
usb usb1: SerialNumber: ffb40000.usb
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver usb-storage
mousedev: PS/2 mouse device common for all mice
i2c /dev entries driver
Bluetooth: Virtual HCI driver ver 1.4
Bluetooth: HCI UART driver ver 2.2
Bluetooth: HCI H4 protocol initialized
Bluetooth: HCI BCSP protocol initialized
Bluetooth: HCILL protocol initialized
Bluetooth: HCIATH3K protocol initialized
Bluetooth: HCI Three-wire UART (H5) protocol initialized
usbcore: registered new interface driver bcm203x
usbcore: registered new interface driver bpa10x
usbcore: registered new interface driver bfusb
usbcore: registered new interface driver btusb
Bluetooth: Generic Bluetooth SDIO driver ver 0.1
usbcore: registered new interface driver ath3k
Synopsys Designware Multimedia Card Interface Driver
cma: dma_alloc_from_contiguous(cma 8084c62c, count 1, align 0)
cma: dma_alloc_from_contiguous(): returned 80c5a820
dwmmc_socfpga ff704000.dwmmc0: Using internal DMA controller.
dwmmc_socfpga ff704000.dwmmc0: Version ID is 240a
dwmmc_socfpga ff704000.dwmmc0: DW MMC controller at irq 171, 32 bit host data width, 1024 deep fifo
dwmmc_socfpga ff704000.dwmmc0: 1 slots initialized
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
oprofile: using arm/armv7-ca9
TCP: cubic registered
NET: Registered protocol family 10
sit: IPv6 over IPv4 tunneling driver
NET: Registered protocol family 17
NET: Registered protocol family 15
can: controller area network core (rev 20120528 abi 9)
NET: Registered protocol family 29
can: raw protocol (rev 20120528)
can: broadcast manager protocol (rev 20120528 t)
can: netlink gateway (rev 20130117) max_hops=1
Bluetooth: RFCOMM TTY layer initialized
Bluetooth: RFCOMM socket layer initialized
Bluetooth: RFCOMM ver 1.11
Bluetooth: BNEP (Ethernet Emulation) ver 1.3
Bluetooth: BNEP filters: protocol multicast
Bluetooth: BNEP socket layer initialized
Bluetooth: HIDP (Human Interface Emulation) ver 1.2
Bluetooth: HIDP socket layer initialized
8021q: 802.1Q VLAN Support v1.8
Key type dns_resolver registered
ThumbEE CPU extension supported.
Registering SWP/SWPB emulation handler
Waiting for root device /dev/mmcblk0p2...
mmc_host mmc0: Bus speed (slot 0) = 50000000Hz (slot req 50000000Hz, actual 50000000HZ div = 0)
mmc0: new high speed SDHC card at address 59b4
mmcblk0: mmc0:59b4 3.72 GiB
mmcblk0: p1 p2 p3
kjournald starting. Commit interval 5 seconds
EXT3-fs (mmcblk0p2): using internal journal
EXT3-fs (mmcblk0p2): recovery complete
EXT3-fs (mmcblk0p2): mounted filesystem with ordered data mode
VFS: Mounted root (ext3 filesystem) on device 179:2.
devtmpfs: mounted
Freeing unused kernel memory: 372K (80777000 - 807d4000)
random: nonblocking pool is initialized
eth0: device MAC address 0e:a9:f1:02:28:ce
cma: dma_alloc_from_contiguous(cma 8084c62c, count 2, align 1)
cma: dma_alloc_from_contiguous(): returned 80c5a840
cma: dma_alloc_from_contiguous(cma 8084c62c, count 2, align 1)
cma: dma_alloc_from_contiguous(): returned 80c5a880


DE0-Nano-SoCに添付されていたMicro SDカードの中身です。Ramdiskではなく、Root File System がセカンダリー・ドライブに入っていました。
DE0-Nano-SoC_2_151018.png
  1. 2015年10月18日 06:01 |
  2. DE0-Nano-SoC
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2015.3 でアンシャープマスキング・フィルタのIP化

Vivado HLS 2015.3 でアンシャープマスキング・フィルタのC/RTL コシミュレーション”が成功したので、IP化を行った。

int 型で予め左シフトして小数を整数にして演算するプロジェクトを最初にIP化する。

IP化するにあたって、現在はインクルード・ヘッダで、”A”の画像に合わせたサイズを unsharp_mask_axis.h に設定してるので、それを 720p に変更した。unsharp_mask_axis.h を示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

#define HORIZONTAL_PIXEL_WIDTH 1280
#define VERTICAL_PIXEL_WIDTH 720

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

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#endif


次に、ブロックレベルのプロトコルが ap_ctrl_hs になっているので、それを ap_ctrl_none に戻した。

これで、もう一度、C から HDL への合成を行った。
unsharp_mask_97_151017.png

unsharp_mask_98_151017.png

BRAM_18K は 8 個、DSE48E は 18 個、FF は 1522 個、LUT は 1629 個使用している。

IP 化を行った。


次は、固定小数点型だ。

同様に、 unsharp_mask_axis.h の画像の大きさを 720p に変更した。unsharp_mask_axis.h を示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

#define HORIZONTAL_PIXEL_WIDTH 1280
#define VERTICAL_PIXEL_WIDTH 720

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

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION 6 // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN 4 // k のビット長
#define NUM_ADC_K 2 // k の小数点の位置

typedef ap_ufixed k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION> y_fixed_td;

#endif


次に、ブロックレベルのプロトコルが ap_ctrl_hs になっているので、それを ap_ctrl_none に戻した。

これで、もう一度、C から HDL への合成を行った。
unsharp_mask_99_151017.png

unsharp_mask_100_151017.png

BRAM_18K は 8 個、DSE48E は 18 個、FF は 2152 個、LUT は 1825 個使用している。やはり、int 型で予め左シフトして小数を整数にして演算するのよりも多くのリソースを使用している。

IP 化を行った。
  1. 2015年10月17日 05:11 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2015.3 でアンシャープマスキング・フィルタのC/RTL コシミュレーション

Vivado HLS 2015.3 でアンシャープマスキング・フィルタのC/RTL コシミュレーションをやってみる。
Vivado HLS 2015.3 では、Open Wave Viewer ... ボタンが追加されていて、このボタンをクリックするとVivado が立ち上がり、C/RTL コシミュレーションの波形を表示してくれる。

まずは、固定小数点型からシミュレーションを行う。
最初にブロックレベルのインターフェースが ap_ctrl_none ではC/RTL コシミュレーションできないので、ap_ctrl_hs に変更した。

#pragma HLS INTERFACE ap_ctrl_hs port=return

これで、C から HDL への合成をやり直してから、Run C/RTL Cosimulation ボタンをクリックしてC/RTL コシミュレーションを行った。
unsharp_mask_90_151016.png

Co-simulation Dialog の Dump Trace の選択項目に port が増えていたので、port に変更した。多分、ポートの波形をDump するのだと思う。
unsharp_mask_93_151016.png

C/RTL コシミュレーションが行われて結果が表示された。
unsharp_mask_90_151016.png

Latency も Interval も 3114 クロックだった。平均2乗誤差もCシミュレーションと同じだ。

Open Wave Viewer ... ボタンをクリックすると、Vivado 2015.3 が立ち上がって、波形が表示された。
unsharp_mask_91_151016.png

波形ウインドウをフロートして、詳しく波形を観察した。
unsharp_mask_92_151016.png

上の波形で ins_TVALID, ins_TREADY と out_TVALID, out_TREADY はアンシャープマスキング・フィルタ処理をしている間は 1 に固定されて、1クロックごとにフィルタ処理を行っているのが分かった。これで問題ないはずだ。

次に、int 型で予め左シフトして小数を整数にして演算するプロジェクトへ変更した。
ここでもブロックレベルのインターフェースを ap_ctrl_none から ap_ctrl_hs に変更した。

これで、C から HDL への合成をやり直してから、Run C/RTL Cosimulation ボタンをクリックしてC/RTL コシミュレーションを行った。

Co-simulation Dialog の Dump Trace の選択項目に port が増えていたので、port に変更した。
unsharp_mask_93_151016.png

C/RTL コシミュレーションが行われて結果が表示された。
unsharp_mask_94_151016.png

Latency も Interval も 3109 クロックだった。こちらのほうがクロック数が少ない。平均2乗誤差もCシミュレーションと同じだ。

mse_b = 0.0108696
mse_g = 0.0125679
mse_r = 0.0288723
mse = 0.0174366


Open Wave Viewer ... ボタンをクリックし、Vivado 2015.3 を立ちあげて波形を表示した。
unsharp_mask_95_151016.png

波形ウインドウをフロートして、詳しく波形を観察した。
unsharp_mask_96_151016.png

固定小数点型の場合と同様に、上の波形で ins_TVALID, ins_TREADY と out_TVALID, out_TREADY はアンシャープマスキング・フィルタ処理をしている間は 1 に固定されて、1クロックごとにフィルタ処理を行っているのが分かった。こちらも問題ない。
  1. 2015年10月16日 04:25 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

アンシャープマスキング・フィルタによる Vivado HLS 2014.4 と Vivado HLS 2015.3 の比較

アンシャープマスキング・フィルタのC++ソースコードによって、Vivado HLS 2014.4 とVivado HLS 2015.3 を比較してみた。

まずは、int 型で予め左シフトして小数を整数にして演算するコードで比較する。同じC++ソースコードを使用する。

最初にVivado HLS 2014.4 のC から HDL への合成結果から示す。
unsharp_mask_78_151015.png
クロック周期のTarget が 10 ns のところ Estimated は 8.22 ns だった。

unsharp_mask_78_151015.png
BRAM_18K が 4 個、DSP48E が 18 個、FF が 1462 個、LUT が 1849 個だった。
Analysis を見るとステート数は32 ステートだった。

次に、Vivado HLS 2015.3 のC から HDL への合成結果を示す。
unsharp_mask_80_151015.png
クロック周期のTarget が 10 ns のところ Estimated は 10.08 ns で、エラーになっている。

unsharp_mask_81_151015.png
BRAM_18K が 2 個、DSP48E が 18 個、FF が 1331 個、LUT が 1575 個だった。Vivado HLS 2014.4 よりも使用リソースは少ない。BRAM も 2 個使用になった。2 ラインしか確保していないので、2 個使用は順当なところだと思う。
Analysis のステート数は 31 ステートだった。

Vivado HLS 2015.3 はステート数も少ないので、もう少しクロック周期の制約を小さな値にしてみる。クロック周期を 8 ns にしてみた。
unsharp_mask_82_151015.png
Estimated は 6.88 ns となった。

unsharp_mask_83_151015.png
BRAM_18K が 2 個、DSP48E が 18 個、FF が 1492 個、LUT が 1575 個だった。FF のみが増えいている。これでもFF、LUT 共にVivado HLS 2014.4 よりも少ない。
Analysis のステート数は 33 ステートだった。


次は、固定小数点型の比較を行う。同じC++ソースコードで比較する。
まずは、Vivado HLS 2014.4 のC から HDL への合成結果から示す。
unsharp_mask_84_151015.png
クロック周期のTarget が 10 ns のところ Estimated は 8.71 ns だった。

unsharp_mask_85_151015.png
BRAM_18K が 4 個、DSP48E が 18 個、FF が 1957 個、LUT が 1993 個だった。
Analysis を見るとステート数は37 ステートだった。

次に、Vivado HLS 2015.3 のC から HDL への合成結果を示す。
unsharp_mask_86_151015.png
クロック周期のTarget が 10 ns のところ Estimated は 10.08 ns で、エラーになっている。

unsharp_mask_87_151015.png
BRAM_18K が 2 個、DSP48E が 18 個、FF が 1603 個、LUT が 1725 個だった。Vivado HLS 2014.4 よりも使用リソースは少ない。やはり、BRAM も 2 個使用になった。
Analysis のステート数は 35 ステートだった。

同様に、Vivado HLS 2015.3 はステート数も少ないので、もう少しクロック周期の制約を小さな値にしてみる。クロック周期を 8 ns にしてみた。
unsharp_mask_88_151015.png
Estimated は 6.65 ns となった。

unsharp_mask_89_151015.png
BRAM_18K が 2 個、DSP48E が 18 個、FF が 2117 個、LUT が 1771 個だった。FF と LUT が増えているが、特に FF の増加が大きい。FF は Vivado HLS 2014.4 よりも多くなった。
Analysis のステート数は 38 ステートだった。

”Vivado HLS 2014.4 vs Vivado HLS 2015.1 vs Vivado HLS 2015.3(AXI4-Stream版ラプラシアンフィルタ IPの比較)”では、Vivado HLS 2015.3 が良かったが、今回は微妙な結果になった。

迷うところではあるが、Vivado HLS 2015.3 を使ってみようかな?と思う。
  1. 2015年10月15日 04:52 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS によるアンシャープマスクキング・フィルタの作製10(ap_int 型による固定小数点)

間に関連の記事は入っているが、一応、”Vivado HLS によるアンシャープマスクキング・フィルタの作製9(C++ の任意精度固定小数点型3)”の続き。

Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)”で、int 型で予め左シフトして小数を整数にして演算するコードを書いた。
今回は、ap_int 型で桁を制限してリソース使用量の低減を図ろうと思う。使用しているVivado HLS のバージョンは、2014.4。

ZYBOのプロジェクトを作って、unsharp_mask_axis.cpp と unsharp_mask_axis.h を ap_int 型に修正した。

unsharp_masking() と unsharp_mask_axis.h を示す。
まずは、unsharp_masking() から。

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
// 2015/09/27 : 演算の小数部は num_adec_k*2 ビットとする。
// 2015/10/14 : ap_int に変更して、演算のビット幅を最適化する
//

#define PRECISION    6    // 小数点以下の桁数、精度(1以上)

int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
    y_td y;
    y_td xy[3][3];
    int result=0;
    int z;

    y_td x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -(xy[0][0]<<PRECISION) -(xy[0][1]<<PRECISION)   -(xy[0][2]<<PRECISION)
            -(xy[1][0]<<PRECISION) +(x1y1*xy[1][1])         -(xy[1][2]<<PRECISION)
            -(xy[2][0]<<PRECISION) -(xy[2][1]<<PRECISION)   -(xy[2][2]<<PRECISION);

        y = (((y_td)k * y)/(y_td)9) >> num_adec_k; // k は num_adc_k だけ左シフトされているので戻す

        y = y + (y_td)(1<<(PRECISION-1)); // 四捨五入 +0.5
        z = y >> PRECISION; // 小数点以下切り捨て

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


unsharp_mask_axis.h を示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_int<6+PRECISION+NUM_ADC_K+8+3> y_td;

#endif


これで、C シミュレーションを行った。
unsharp_mask_75_151014.png

平均2乗誤差も int 型で予め左シフトして小数を整数にして演算した時と同じだ。

次に、C++ から HDL へ合成を行った。結果を示す。
unsharp_mask_76_151014.png

unsharp_mask_77_151014.png

BRAM_18K は 4 個、DSP48E は 24 個、FF は 1489 個、LUT は 1812 個のリソースを消費した。

Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)”で、int 型で予め左シフトして小数を整数にして演算した時のリソース使用量は、
BRAM_18K は 4 個、DSP48E は 18 個、FF は 1462 個、LUT は 1849 個だったので、
LUT は37 個減ったが、FF が 27 個、DSP48E は 6 個増えてしまった。

う~ん。これでは int 型を使ったほうが良さそうだ。
  1. 2015年10月14日 03:57 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLSにおける固定小数点の誤差を平均2乗誤差で算出する

Vivado HLS 2014.4 で int 型で予め左シフトして小数を整数にして演算したり、固定小数点型を使って小数点を含んだ演算をしてきた。今までフィーリングでこれで大丈夫かな?と判定してきたが、流石になにか判定基準が欲しい。

そこで、平均2乗誤差を導入することにした。平均2乗誤差 MSE (mean squared error) を次に式で求めることにする。(「二乗誤差とPSNR」を参照させて頂いた)

Σ((浮動小数点数のアンシャープマスキング・フィルタ処理値) - (固定小数点のアンシャープマスキング・フィルタ処理値))の2乗) / (総画素数 - 2行分の画素)

分母だが、最上位の2行は元の画素値なので、それを含めない画素数とした。

これを計算して見ると、固定小数点型を使用した場合の

ap_ufixed<8, 8, AP_RND, AP_SAT> z;

と定義した時の平均2乗誤差を示す。(C シミュレーション結果)
unsharp_mask_70_151013.png

mse_b = 0.00679348
mse_g = 0.00679348
mse_r = 0.0078125
mse = 0.00713315

となった。
なお、mse_b が青の平均2乗誤差、mse_g が緑の平均2乗誤差、mse_r が赤の平均2乗誤差、mse がその3色の平均2乗誤差となる。

次に、

ap_ufixed<8, 8, AP_TRN, AP_SAT> z;

と定義した時の平均2乗誤差は、

mse_b = 0.0108696
mse_g = 0.0125679
mse_r = 0.0288723
mse = 0.0174366

となって、AP_RND よりも大きくなった。(C シミュレーション結果)
unsharp_mask_71_151013.png

次に、 int 型で予め左シフトして小数を整数にして演算した時の平均2乗誤差を示す。(C シミュレーション結果)
unsharp_mask_72_151013.png

mse_b = 0.0108696
mse_g = 0.0125679
mse_r = 0.0288723
mse = 0.0174366

固定小数点型で量子化モードが AP_TRN の時の平均2乗誤差と同じになった。

ちなみに、 int 型で予め左シフトして小数を整数にして演算した時で、PRECISION を 8 にした時の平均2乗誤差を示す。(今までは 6。C++ソースコード参照

mse_b = 0.00611413
mse_g = 0.00577446
mse_r = 0.0115489
mse = 0.0078125


どの辺りの平均2乗誤差を目指そうか?迷うが、PRECISION = 8 のアンシャープマスキング・フィルタ画像と PRECISION = 6 のアンシャープマスキング・フィルタ画像がほとんど変わらないので、 PRECISION = 6 の時の平均2乗誤差を目標としよう。
つまり、固定小数点での量子化モードはAP_TRN にする事になる。

PRECISION = 8 のアンシャープマスキング・フィルタ画像を示す。(K = 2.5)
unsharp_mask_73_151013.png

PRECISION = 6 のアンシャープマスキング・フィルタ画像を示す。(K = 2.5)
unsharp_mask_74_151013.png

平均2乗誤差を取る付近の unsharp_mask_axis_tb.cpp のコードを下に示す。

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    double mse = 0;    // 全体の平均2乗誤差
    double mse_r = 0;    // 赤の平均2乗誤差
    double mse_g = 0;    // 緑の平均2乗誤差
    double mse_b = 0;    // 青の平均2乗誤差
    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;

            hw_usmd[(j*bmpihr.biWidth)+i] = (int)val;

            if (val != val_soft){
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
                //return(1);
            }
            if (vals.last)
                cout << "AXI-Stream is end" << endl;
            mse_b += pow(((val_soft & 0xff) - (val & 0xff)), 2.0);
            mse_g += pow((((val_soft>>8)&0xff) - ((val>>8)&0xff)), 2.0);
            mse_r += pow((((val_soft>>16)&0xff) - ((val>>16)&0xff)), 2.0);
        }
    }
    mse_b = mse_b/(bmpihr.biWidth*(bmpihr.biHeight-2)); // 2行は元の画素値なので、平均から外す
    mse_g = mse_g/(bmpihr.biWidth*(bmpihr.biHeight-2)); // 2行は元の画素値なので、平均から外す
    mse_r = mse_r/(bmpihr.biWidth*(bmpihr.biHeight-2)); // 2行は元の画素値なので、平均から外す
    mse = (mse_b + mse_g + mse_r)/3;
    cout << "mse_b = " << mse_b << endl;
    cout << "mse_g = " << mse_g << endl;
    cout << "mse_r = " << mse_r << endl;
    cout << "mse = " << mse << endl;
    //cout << "Success HW and SW results match" << endl;
    cout << endl;

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

バクマン(映画)を見てきました

今日は下の娘と奥さんとバクマン(映画)を見てきました。コミックとストーリーが少し違っていましたが、なかなか面白かったです。主題歌も良かったですよ。
  1. 2015年10月12日 22:08 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2015.3 の半精度浮動小数点数でアンシャープマスキング・フィルタを作った

Vivado HLS 2015.3 の半精度浮動小数点数でアンシャープマスキング・フィルタを作った。

Vivado HLS によるアンシャープマスクキング・フィルタの作製2(floatで実装してみた)”で使った浮動小数点数をVivado 2015.3 から実装された半精度浮動小数点数に変更してやってみた。
半精度浮動小数点数 half はhls_half.h をインクルードすると使用することができる。

Cシミュレーションの結果を示す。K = 2.5 の場合だ。
unsharp_mask_61_151011.png

テストベンチのアンシャープマスキング・フィルタの演算は float なので、half との間の誤差は出ている。

次に、C から HDL への合成結果を示す。
unsharp_mask_62_151011.png

unsharp_mask_63_151011.png

DSP48E が 141 % 、FF が 103 %、LUT が 313 % でいずれもZYBO の Zynq-7010 のFPGAのリソースをオーバーしている。

float で実装した時と比べると、リソース使用量は減っているが、やはりリソース使用量は多いといえる。Zynq-7010 には入らない。
float で実装した時のリソース使用量を下に示す。
unsharp_mask_8_150926.png

半精度浮動小数点数を使っても、ZYBO にアンシャープマスキング・フィルタが入らないということが分かった。残念。。。

下に使用したC++ソースコードを示す。

最初に、unsharp_mask_axis.h を示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

#endif


次に、unsharp_mask_axis_halffp.cpp を示す。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// 2015/10/11 : Half-Precision Floating-Point Data Types Version
//

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

#include "unsharp_mask_axis.h"

int unsharp_masking(int pix_mat[3][3], ap_uint<K_BITLEN> k);

int unsharp_mask_axis(ap_uint<1> usm_fil_enable, ap_uint<K_BITLEN> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE ap_none port=usm_fil_enable
#pragma HLS INTERFACE ap_none port=usm_fil_k
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_none port=return

    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> usm;

    int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete

    int usm_fil_val;

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            for (int i=0; i<3; i++){
                for (int j=0; j<2; j++){
#pragma HLS UNROLL
                    pix_mat[i][j] = pix_mat[i][j+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            pix_mat[2][2] = pix.data;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = pix.data;

            usm.data = unsharp_masking(pix_mat, usm_fil_k);

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
                usm.data = pix.data;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                usm.user = 1;
            else
                usm.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                usm.last = 1;
            else
                usm.last = 0;

            if (usm_fil_enable)
                outs << usm;    // AXI4-Stream へ出力
            else
                outs << pix;    // 入力画像をそのまま出力
        }
    }

    return 0;
}

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// K_BITLEN : 鮮鋭化の強さ(固定小数点)
// NUM_ADC_K : Kの小数点の位置
//
int unsharp_masking(int pix_mat[3][3], ap_uint<K_BITLEN> k)
{
    half y;
    int xy[3][3];
    half rgb[3];
    int result=0;

    half fk = (half)k;
    for (int m=0; m<NUM_ADC_K; m++){ // 小数点の位置を正しい位置にする
        fk /= 2.0;
    }

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }
        y = -(half)xy[0][0]         -(half)xy[0][1]      -(half)xy[0][2]
            -(half)xy[1][0] +(9.0/fk+8.0)*(half)xy[1][1] -(half)xy[1][2]
            -(half)xy[2][0]         -(half)xy[2][1]      -(half)xy[2][2];
        y = (fk * y)/9.0;

        int z = (int)(y + 0.5);    // 四捨五入

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


最後に、unsharp_mask_axis_tb.cpp を示す。

// unsharp_mask_axis_tb.cpp
// 2015/09/26 by marsee
//

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

#include "bmp_header.h"
#include "unsharp_mask_axis.h"

int unsharp_mask_axis(ap_uint<1> usm_fil_enable, ap_uint<K_BITLEN> k_fixed, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);

int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k);
int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);

#define CLOCK_PERIOD 10

#define K 2.5 // 鮮鋭化の強さ
#define NUM_ADEC_K 2 // Kの小数点の位置

int main()
{
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;

    int m_seq = 1// M系列の値
    int i;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int *rd_bmp, *hw_usmd;
    int blue, green, red;

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

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

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
           pix.user = 0;
         pix.data = i;
        ins << pix;
    }

    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];

            if (j==0 && i==0)    // 最初のデータの時に TUSER を 1 にする
                pix.user = 1;
            else
                pix.user = 0;

            if (i == bmpihr.biWidth-1// 行の最後でTLASTをアサートする
                pix.last = 1;
            else
                pix.last = 0;

            ins << pix;
            ins_soft << pix;
        }
    }

    int usm_k = (int)(K * pow(2.0, (double)NUM_ADEC_K));
    unsharp_mask_axis(1, (ap_uint<K_BITLEN>)K, ins, outs);
    unsharp_mask_axis_soft(1, usm_k, ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight); // k = 2;

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;

            hw_usmd[(j*bmpihr.biWidth)+i] = (int)val;

            if (val != val_soft){
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
                //return(1);
            }
            if (vals.last)
                cout << "AXI-Stream is end" << endl;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ハードウェアのラプラシアンフィルタの結果を temp_usm.bmp へ出力する
    if ((fbmpw=fopen("temp_usm.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_usm.bmp by binary write mode\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);

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

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);
    free(rd_bmp);
    free(hw_usmd);

    return 0;
}

int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> usm;
    int **line_buf;
    int pix_mat[3][3];
    int usm_fil_val;
    int i;

    // line_buf の1次元目の配列をアロケートする
    if ((line_buf =(int **)malloc(sizeof(int *) * 2)) == NULL){
        fprintf(stderr, "Can't allocate line_buf[3][]\n");
        exit(1);
    }

    // メモリをアロケートする
    for (i=0; i<2; i++){
        if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
            fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
            exit(1);
        }
    }

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix; // AXI4-Stream からの入力

            for (int k=0; k<3; k++){
                for (int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            pix_mat[2][2] = pix.data;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = pix.data;

            usm.data = unsharp_masking_soft(pix_mat, (int)usm_fil_k, 2);

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
                usm.data = pix.data;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                usm.user = 1;
            else
                usm.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                usm.last = 1;
            else
                usm.last = 0;

            if (usm_fil_enable)
                outs << usm;    // AXI4-Stream へ出力
            else
                outs << pix;    // 入力画像をそのまま出力
        }
    }

    for (i=0; i<2; i++)
        free(line_buf[i]);
    free(line_buf);

    return 0;
}

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点)
// num_adec_k : Kの小数点の位置
//
int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k)
{
    float y;
    int xy[3][3];
    float rgb[3];
    int result=0;

    float fk = (float)k;
    for (int m=0; m<num_adec_k; m++){ // 小数点の位置を正しい位置にする
        fk /= 2.0;
    }

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }
        y = -(float)xy[0][0]         -(float)xy[0][1]      -(float)xy[0][2]
            -(float)xy[1][0] +(9.0/fk+8.0)*(float)xy[1][1] -(float)xy[1][2]
            -(float)xy[2][0]         -(float)xy[2][1]      -(float)xy[2][2];
        y = (fk * y)/9.0;

        int z = (int)(y + 0.5); // 四捨五入

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}

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

Vivado HLS によるアンシャープマスクキング・フィルタの作製9(C++ の任意精度固定小数点型3)

Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)”の続き。

前回、int 型で予め左シフトして小数を整数にして演算するよりも、固定小数点型にしたほうが、LUT 使用量は減ったが、FF 使用量は増えた。

今回は、固定小数点型で更にリソース使用量の削減、レイテンシの削減を図る。使用しているのは Vivado HLS 2014.4 。
(2015/10/13:C++ソースコードが間違っていたので、修正した)

まずは、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2015.1) 2015 年 4 月 1 日”の550ページ ” C++ の任意精度固定小数点型”を読むと、固定小数点型のデフォルトの量子化モードは AP_TRN、デフォルトのオーバーフロー・モードは AP_WRAP に指定されている。
量子化モードの AP_TRN は切り捨てで、オーバーフロー・モードの AP_WRAP は折り返しと、後での演算が必要無いモードになっている気がする。
今の固定小数点のモードは、量子化モードは AP_RND で、正の無限大への丸め、オーバーフロー・モードは AP_SAT で飽和にしている。これを本当に飽和演算の必要な z 以外はデフォルトにすることにした。
更に、z を飽和演算は必要なので、オーバーフロー・モードは AP_SAT の飽和だが、量子化モードを AP_TRN にしてみる。

これで、C から HDL への合成を行った。結果を下に示す。
unsharp_mask_51_151010.png

unsharp_mask_52_151010.png
FF 使用量は 1997 個だった。LUT 使用量は 1993 個だった。”Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)”の時の、FF 使用量が 2304 個、LUT 使用量が 2835 個の時よりも少なくなっている。

Analysis 結果を示す。
unsharp_mask_53_151010.png

unsharp_mask_54_151010.png
36 ステートだった。

順番が逆になったが、Cシミュレーションを行った。
unsharp_mask_55_151010.png
誤差が大きくなってしまった。

次に z の量子化モードを AP_RND に戻す。
これで、Cシミュレーションを行った。
unsharp_mask_56_151010.png
問題ないようだ。

C から HDL への合成を行った。
unsharp_mask_57_151010.png

unsharp_mask_58_151010.png
FF 使用量は 1966 個、LUT 使用量は 2131 個で、 z の量子化モードが AP_TRN の場合ののリソース使用量よりも増えている。

Analysis 結果を示す。
unsharp_mask_59_151010.png

unsharp_mask_60_151010.png
36 ステートだった。 z の量子化モードが AP_TRN の場合と同じだ。

ほとんどの固定小数点型の数はオーバーフローしないようにビット長を決定しているので、量子化モードやオーバーフロー・モードは関係ないので、演算が軽いデフォルトで使用する。最後に飽和演算が必要な場合にだけ、必要な量子化モードとオーバーフロー・モードを設定したほうが良いと思う。

最後に、unsharp_masking() を示す。

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
//

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1;
    y_fixed_td y;
    
    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -xy[0][0]    -xy[0][1]        -xy[0][2]
            -xy[1][0]    +x1y1*xy[1][1]    -xy[1][2]
            -xy[2][0]    -xy[2][1]        -xy[2][2];

        y = (k_fixed * y)/(y_fixed_td)9;

        y = y+(y_fixed_td)0.5// 四捨五入
        if (y < 0)
            z = 0;
        else if (y > 255)
            z = 255;
        else
            z = y;

        result += z.to_int()<<i; // i=0 : blue, i=8 : green, i=16 : red
    }
    return(result);
}


次に、unsharp_mask_axis.h を下に示す。

// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_ufixed<K_BITLEN, K_BITLEN-NUM_ADC_K> k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION> y_fixed_td;

#endif

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

Vivado HLS 2014.4 vs Vivado HLS 2015.1 vs Vivado HLS 2015.3(AXI4-Stream版ラプラシアンフィルタ IPの比較)

今年(2015年)の5月8日に、”Vivado HLS 2014.4 vs Vivado HLS 2015.1 vs Vivado HLS 2015.3(AXI4-Stream版ラプラシアンフィルタ IPの比較)”という記事を書いたが、今回はその記事をコピーして、そこに、新しく出たVivado HLS 2015.3 の結果を追加してみようと思う。

AXI4-Stream版ラプラシアンフィルタ IPで、Vivado HLS 2014.4 と Vivado HLS 2015.1 と Vivado HLS 2015.3 の高位合成結果を比較してみた。

C++ ソースコードは、すべて同じもので、”Vivado 2014.4 でAXI4-Stream版ラプラシアンフィルタIP を作製する1(C++ ソースコードの公開)”で示したものだ。但し、lap_filter_axis.h は実際の 800 x 600 ピクセルに変更した。lap_filter_axis.h を下に示す。

// lap_filter_axis.h
// 2015/05/01

#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600

// #define HORIZONTAL_PIXEL_WIDTH 50
// #define VERTICAL_PIXEL_WIDTH 10

#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)


クロック周期 10 ns
・Vivado HLS 2014.4
クロック周期 10 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。
lap_filter_AXIS_52_150507.png
Timing の Estimated は 7.58 ns だった。FF は 382 個、LUT は 626 個使用している。

・Vivado HLS 2015.1
クロック周期 10 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_53_150507.png
Timing の Estimated は 9.40 ns だった。FF は 387 個、LUT は 556 個使用している。

・Vivado HLS 2015.3
クロック周期 10 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_66_151008.png 
Timing の Estimated は 6.91 ns だった。FFは 411 個、LUTは 445 個を使用している。
FFは3つのバージョンの中で一番多いが、LUTは一番少ない。FFとLUTの数がバランスしている方がFPGAのSliceを有効に使えて良いと思う。


クロック周期 9 ns
・Vivado HLS 2014.4
クロック周期 9 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。
lap_filter_AXIS_54_150507.png
Timing の Estimated は 7.58 ns だった。FF は 382 個、LUT は 626 個使用している。つまり、クロック周期が 10 ns の時と同じ回路だと思う。

・Vivado HLS 2015.1
クロック周期 9 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_55_150507.png
Timing の Estimated は 9.40 ns で、クロック周期 9 ns に対して遅くなりエラーになっている。FF は 387 個、LUT は 556 個使用している。これも、クロック周期が 10 ns の時と同じ回路だと思う。

・Vivado HLS 2015.3
クロック周期 9 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_67_151008.png 
Timing の Estimated は 6.91 ns だった。FFは 411 個、LUTは 445 個を使用している。クロック周期が 10 ns の時と同じ回路だ。クロック周期が 6.91 ns なので、回路を変える必要はない。


クロック周期 8 ns
・Vivado HLS 2014.4
クロック周期 8 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。
lap_filter_AXIS_56_150507.png
Timing の Estimated は 6.91 ns だった。FF は 435 個、LUT は 627 個使用している。今回は回路が変更されているようだ。

・Vivado HLS 2015.1
クロック周期 8 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_57_150507.png
Timing の Estimated は 9.40 ns で、クロック周期 8 ns に対して遅くなりエラーになっている。FF は 436 個、LUT は 556 個使用している。FF が増えているので回路は変更されているようだ。

・Vivado HLS 2015.3
クロック周期 8 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_68_151008.png 
Timing の Estimated は 6.91 ns だった。FFは 411 個、LUTは 445 個を使用している。クロック周期が 10 ns の時と同じ回路だ。クロック周期が 6.91 ns なので、回路を変える必要はない。


クロック周期 7 ns
・Vivado HLS 2014.4
クロック周期 7 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。
lap_filter_AXIS_58_150507.png
Timing の Estimated は 6.88 ns だった。FF は 455 個、LUT は 627 個使用している。今回も回路が変更されているようだ。

・Vivado HLS 2015.1
クロック周期 7 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_59_150507.png
Timing の Estimated は 8.77 ns で、クロック周期 8 ns に対して遅くなりエラーになっている。FF は 455 個、LUT は 564 個使用している。FF が増えているので回路は変更されているようだ。

・Vivado HLS 2015.3
クロック周期 7 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_69_151008.png 
Timing の Estimated は 6.88 ns だった。FFは 491 個、LUTは 455 個を使用している。初めて、FF、LUT 共に増えた。


クロック周期 6 ns
・Vivado 2014.4
クロック周期 6 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。
lap_filter_AXIS_60_150507.png
Timing の Estimated は 6.88 ns で、クロック周期 6 ns に対して遅くなりエラーになっている。FF は 473 個、LUT は 637 個使用している。

・Vivado HLS 2015.1
クロック周期 6 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_61_150507.png
Timing の Estimated は 6.88 ns で、クロック周期 6 ns に対して遅くなりエラーになっている。FF は 473 個、LUT は 566 個使用している。

・Vivado HLS 2015.3
クロック周期 6 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_70_151008.png 
Timing の Estimated は 6.88 ns で、クロック周期 6 ns に対して遅くなりエラーになっている。FF は 509 個、LUT は 465 個使用している。FF、LUT 共にクロック周期が 7 ns の時よりも増えていて、回路が変わっているようだが、Estimaed は同じでここで限界なのかもしれない?


クロック周期 2.5 ns
・Vivado HLS 2014.4
クロック周期 2.5 ns で Vivado HLS 2014.4 で高位合成を行った結果を示す。限界を見極めるためだ。
lap_filter_AXIS_62_150507.png
Timing の Estimated は 6.88 ns で、クロック周期 2.5 ns に対して遅くなりエラーになっている。FF は 1367 個、LUT は 693 個使用している。これだけFFを使用してもタイミングを満たさないので、ここが限界のようだ。

・Vivado HLS 2015.1
クロック周期 2.5 ns で Vivado HLS 2015.1 で高位合成を行った結果を示す。
lap_filter_AXIS_63_150507.png
Timing の Estimated は 6.88 ns で、クロック周期 2.5 ns に対して遅くなりエラーになっている。FF は 1335 個、LUT は 622 個使用している。これだけFFを使用してもタイミングを満たさないので、こちらもここが限界のようだ。

・Vivado HLS 2015.3
クロック周期 2.5 ns で Vivado HLS 2015.3 で高位合成を行った結果を示す。
lap_filter_AXIS_71_151008.png
Timing の Estimated は 6.88 ns で、クロック周期 2.5 ns に対して遅くなりエラーになっている。FF は 1333 個、LUT は 646 個使用している。これだけFFを使用してもタイミングを満たさないので、ここが限界のようだ。

Vivado HLS 2015.3 は FF の使用量は多いものの、LUTの使用量は少ない。但し、クロック周期 2.5 ns を除けば、FF とLUT の数は大体同じようなので、バランスが良いと言える。今後はVivado HLS 2014.4 の代わりにVivado 2015.3 を使いたいと思う。

  1. 2015年10月09日 04:54 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2015.3 が出た

Vivado HLS 2015.3 が出た。普通は”Vivado 2015.3 が出た”と書くと思うのだが、なるべくVivado HLS を使っていこうと思っている私にとって、Vivado HLS が新しくなったのが大きなニュースだ。

今度のVivado HLS は1つのテストしかしていないが、今まで使ってきたVivado HLS 2014.4 よりも良くなっていると思う。今やっている固定小数点型の比較が終わった時点でVivado HLS 2015.3 に乗り換えたいと思う。

まずは、2015.3のリリースノートはまだ日本語がないので、英語の2015.3のリリースノートを参照している。10ページにVivado HLS の新機能が書いてある。
それによると、

・Open Wave Viewer toolbar buttonが付いた
・半精度の浮動小数点数が hls_half.h をインクルードすることで使えるようなった。
・DATAFLOW ディレクティブが改善された。
・AXI4 master (m_axi)がループ内で自動でバースト転送を推論してくれるようになった。
・config_interface でのAXI-Stream (axis) のレジスタ・オプション
・AXI-Lite (s_axilite) に独自クロックを割り当てられるようになった。
・新しいリソース・コア・オプション(Mul_LUT)

だそうだ

一番、大きな変更は、Vivado HLS 2015.3 ではOpen Wave Viewer toolbar button が付いたことだ。今まで、Vivado を立ちあげて、Tcl Console からTcl コマンドを入力してとやっていたが、Open Wave Viewer toolbar button をクリックすれば、それらを全部やってくれて、Vivado が立ち上がり波形を表示することができる。
Vivado_HLS_2015_3_1_151008.png

Vivado_HLS_2015_3_4_151008.png

次に、AXI-Lite (s_axilite) に独自クロックを調べてみた。
AXI4 Stream にAXI4 Lite Slave インターフェースが付いている回路で、AXI4 Lite Slave インターフェースに独自クロックを追加する。
C++ソースコードで、s_axilite ディレクティブを編集する。
Vivado_HLS_2015_3_2_151008.png

Vivado HLS Directive Editor で clock name (optional) に axils_clk を入力した。
Vivado_HLS_2015_3_3_151008.png

すると、s_axilite ディレクティブに”clock=axils_clk”が追加された。
Vivado_HLS_2015_3_5_151008.png

C から HDL へ合成を行った。
Vivado_HLS_2015_3_6_151008.png

lap_filter_axis.v を見ると、”axils_clk”と”ap_rst_n_axils_clk”が追加されている。
Vivado_HLS_2015_3_7_151008.png

lap_filter_axis.v のモジュール宣言を貼っておく。

module lap_filter_axis (
        ap_clk,
        ap_rst_n,
        ins_TDATA,
        ins_TVALID,
        ins_TREADY,
        ins_TKEEP,
        ins_TSTRB,
        ins_TUSER,
        ins_TLAST,
        ins_TID,
        ins_TDEST,
        outs_TDATA,
        outs_TVALID,
        outs_TREADY,
        outs_TKEEP,
        outs_TSTRB,
        outs_TUSER,
        outs_TLAST,
        outs_TID,
        outs_TDEST,
        s_axi_AXILiteS_AWVALID,
        s_axi_AXILiteS_AWREADY,
        s_axi_AXILiteS_AWADDR,
        s_axi_AXILiteS_WVALID,
        s_axi_AXILiteS_WREADY,
        s_axi_AXILiteS_WDATA,
        s_axi_AXILiteS_WSTRB,
        s_axi_AXILiteS_ARVALID,
        s_axi_AXILiteS_ARREADY,
        s_axi_AXILiteS_ARADDR,
        s_axi_AXILiteS_RVALID,
        s_axi_AXILiteS_RREADY,
        s_axi_AXILiteS_RDATA,
        s_axi_AXILiteS_RRESP,
        s_axi_AXILiteS_BVALID,
        s_axi_AXILiteS_BREADY,
        s_axi_AXILiteS_BRESP,
        interrupt,
        axils_clk,
        ap_rst_n_axils_clk
);


AXI4 Lite Slave インターフェースの独自クロックのタイミング制約を何処でするか?はまだわかっていない。
  1. 2015年10月08日 05:22 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:2

Vivado HLS によるアンシャープマスクキング・フィルタの作製8(C++ の任意精度固定小数点型2)

Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)”の続き。

前回はC++のソースコードを公開した。今回は、Cシミュレーションを行ってから、C++ から HDL への合成を行って、int 型でシフトを使って演算した実装と比較する。

(2015/10/13:全面的に修正)

まずは、Cシミュレーションを行った。int 型でシフトを使って演算のCシミュレーション結果よりも精度が良い。
unsharp_mask_42_151006.png

固定小数点型で書いた今回のC++ ソースコードを HDL へ合成した。下に結果を示す。
unsharp_mask_43_151006.png

unsharp_mask_44_151007.png
BRAM_18K は 4 個、DSP48E は 18 個、FF は 2304 個、LUT は 2835 個使用している。

次に、int 型でシフトを使ってアンシャープマスキング・フィルタの演算を行った例として”Vivado HLS によるアンシャープマスクキング・フィルタの作製3(固定小数点で実装してみた)”の unsharp_masking() を固定小数点型での実装と同様に、x1y1 をループの外に出した。
unsharp_masking() を示す。

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
// 2015/09/27 : 演算の小数部は num_adec_k*2 ビットとする。
//

#define PRECISION    6    // 小数点以下の桁数、精度(1以上)

int unsharp_masking(int pix_mat[3][3], int k, int num_adec_k)
{
    int y;
    int xy[3][3];
    int result=0;
    int z;

    int x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -(xy[0][0]<<PRECISION) -(xy[0][1]<<PRECISION) -(xy[0][2]<<PRECISION)
            -(xy[1][0]<<PRECISION) +x1y1*xy[1][1]         -(xy[1][2]<<PRECISION)
            -(xy[2][0]<<PRECISION) -(xy[2][1]<<PRECISION) -(xy[2][2]<<PRECISION);

        y = ((k * y)/9) >> num_adec_k; // k は num_adc_k だけ左シフトされているので戻す

        z = y + (1<<(PRECISION-1)); // 四捨五入 +0.5
        z = z >> PRECISION; // 小数点以下切り捨て

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


これで、C++ からHDL への合成を行った。結果を示す。
unsharp_mask_45_151007.png

unsharp_mask_46_151007.png
BRAM_18K は 4 個、DSP48E は 18 個、FF は 1462 個、LUT は 1849 個使用している。

FF も LUT も、固定小数点の方が多い。
FF と LUT が固定小数点型の方が増えているのは、次に示すAnalysis の結果でもわかるが、パイプラインの段数が増えているからではないか?と思う。

固定小数点型での、Analysis 結果を示す。
unsharp_mask_47_151007.png

unsharp_mask_48_151007.png
C40 まである。

int 型でシフトを使ってアンシャープマスキング・フィルタの演算を行った例のAnalysis 結果を示す。
unsharp_mask_49_151007.png

unsharp_mask_50_151007.png

C31 までで、固定小数点型よりも 9 ステージ少ない。
  1. 2015年10月07日 04:17 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS によるアンシャープマスクキング・フィルタの作製7(C++ の任意精度固定小数点型)

Vivado HLS によるアンシャープマスクキング・フィルタの作製4(固定小数点で実装してみた2)”の固定小数点は自分で小数点の位置を管理していた。

今回は、Vivado HLS に備わっている C++ の任意精度固定小数点型で書いてみようと思う。C++ の任意精度固定小数点型については、”Vivado Design Suite ユーザー ガイド 高位合成 UG902 (v2015.1) 2015 年 4 月 1 日”の550ページ ” C++ の任意精度固定小数点型”を参照のこと。

(2015/10/13:C++ソースコードを書き換えました)

小数点以下の数は前回同様にPRECISION で指定するので、整数部分を決定しようと思う。
num_adec_k(Kの小数点の位置)は、define で定義された NUM_ADEC_K に変更しようと思う。
NUM_ADEC_K が大きければ、小さい小数がありえて、例えばNUM_ADEC_K = 2 だと、0.25が最小値だが、k で割るところでは値が4倍になる。NUM_ADEC_K が8だったら、256倍になる可能性がある。(k は0以外)
よって、

iint x1y1 = (9<<(PRECISION+num_adec_k))/k + (8<<PRECISION);

は、

ap_ufixed<5+PRECISION+NUM_ADC_K, (5+PRECISION+NUM_ADC_K)-PRECISION, AP_RND, AP_SAT> x1y1 = 9/k_fixed + 8;

に変更した。

バグが出てデバックしていたが原因が分かった。今のところ、int型から固定小数点型への変換がうまく行っていないのと、整数リテラルと相対的に精度の低い固定小数点型の演算の結果を精度の高い固定小数点型に入れると桁落ちするようだ。

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88, AP_RND, AP_SAT> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1, x1y1_2;
    ap_ufixed<5+PRECISION+NUM_ADC_K+8+3, (5+PRECISION+NUM_ADC_K+8+3)-PRECISION, AP_RND, AP_SAT> y;
    
    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある
    x1y1_2 = 9/k_fixed + 8;

    cout << "x1y1 = " << x1y1 << endl;
    cout << "x1y1_2 = " << x1y1_2 << endl;


一部抜粋だが、この結果は下に示すようになった。

Compiling ../../../unsharp_mask_axis_tb.cpp in debug mode
Compiling ../../../unsharp_mask_axis.cpp in debug mode
Generating csim.exe
x1y1 = 10.5625
x1y1_2 = 10
x1y1 = 10.5625
x1y1_2 = 10


ちなみに typedef を下に示す。

typedef ap_ufixed


int型から固定小数点型への変換がうまく行かない件は最初から固定小数点型をハードウェア化する関数に渡すように変更した。
つまり、ハードウェア化するとポートになるということだが、うまく4ビット幅の入力ポートになった。これで使える。
但し、ap_ufixed<8, 8, AP_RND, AP_SAT> z; とか小数部分が無い固定小数点型ならば int型から代入しても問題ないようだ。

ソースを貼っておこうと思う。
まずは unsharp_mask_axis.h から貼っておく。
// unsharp_mask_axis.h
// 2015/09/26 by marsee

#ifndef __UNSHARP_MASK_AXIS_H_
#define __UNSHARP_MASK_AXIS_H_

//#define HORIZONTAL_PIXEL_WIDTH    1280
//#define VERTICAL_PIXEL_WIDTH    720

#define HORIZONTAL_PIXEL_WIDTH    64
#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PRECISION    6    // 小数点以下の桁数、精度(0 以上の数を指定する)
#define K_BITLEN    4    // k のビット長
#define NUM_ADC_K    2    // k の小数点の位置

typedef ap_ufixed<K_BITLEN, K_BITLEN-NUM_ADC_K> k_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K, (6+PRECISION+NUM_ADC_K)-PRECISION, AP_RND, AP_SAT> x1y1_fixed_td;
typedef ap_fixed<6+PRECISION+NUM_ADC_K+8+3, (6+PRECISION+NUM_ADC_K+8+3)-PRECISION, AP_RND, AP_SAT> y_fixed_td;

#endif


次に、 unsharp_mask_axis.cpp を貼っておく。

// unsharp_mask_axis.cpp
// 2015/09/24 by marsee
// ap_fixedバージョン 2015/10/04
//

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

#include "unsharp_mask_axis.h"

using namespace std;

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed);

int unsharp_mask_axis(ap_uint<1> usm_fil_enable, k_fixed_td k_fixed, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE ap_none port=usm_fil_enable
#pragma HLS INTERFACE ap_none port=k_fixed
#pragma HLS INTERFACE axis port=ins
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_none port=return

    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> usm;

    int line_buf[2][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=2 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    int pix_mat[3][3];
#pragma HLS array_partition variable=pix_mat complete

    int usm_fil_val;

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            for (int i=0; i<3; i++){
                for (int j=0; j<2; j++){
#pragma HLS UNROLL
                    pix_mat[i][j] = pix_mat[i][j+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            pix_mat[2][2] = pix.data;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = pix.data;

            usm.data = unsharp_masking(pix_mat, k_fixed);

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
                usm.data = pix.data;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                usm.user = 1;
            else
                usm.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                usm.last = 1;
            else
                usm.last = 0;

            if (usm_fil_enable)
                outs << usm;    // AXI4-Stream へ出力
            else
                outs << pix;    // 入力画像をそのまま出力
        }
    }

    return 0;
}

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点) , k != 0
// num_adec_k : Kの小数点の位置
//

int unsharp_masking(int pix_mat[3][3], k_fixed_td k_fixed)
{
    ap_ufixed<88, AP_RND, AP_SAT> xy[3][3];
    int result=0;
    ap_ufixed<88, AP_RND, AP_SAT> z;
    x1y1_fixed_td x1y1;
    y_fixed_td y;
    /*ap_ufixed<8, 8> xy[3][3];    int result=0;    ap_ufixed<8, 8, AP_RND, AP_SAT> z;    x1y1_fixed_td x1y1;    y_fixed_td y;*/
    
    x1y1 = (x1y1_fixed_td)9/(x1y1_fixed_td)k_fixed + (x1y1_fixed_td)8// ビット長は 9+8 が2^5=32 より小さく、k_fixedで割るので、NUM_ADC_Kが増える可能性がある

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }

        y = -xy[0][0]    -xy[0][1]        -xy[0][2]
            -xy[1][0]    +x1y1*xy[1][1]    -xy[1][2]
            -xy[2][0]    -xy[2][1]        -xy[2][2];

        y = (k_fixed * y)/(y_fixed_td)9;

        y = y+(y_fixed_td)0.5// 四捨五入
        if (y < 0)
            z = 0;
        else if (y > 255)
            z = 255;
        else
            z = y;

        result += z.to_int()<<i; // i=0 : blue, i=8 : green, i=16 : red
    }
    return(result);
}


最後に、unsharp_mask_axis_tb.cpp を貼っておく。

// unsharp_mask_axis_tb.cpp
// 2015/09/26 by marsee
//

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

#include "bmp_header.h"
#include "unsharp_mask_axis.h"

int unsharp_mask_axis(ap_uint<1> usm_fil_enable, k_fixed_td k_fixed, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);

int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k);
int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height);

#define CLOCK_PERIOD 10

#define K 2.5 // 鮮鋭化の強さ
#define NUM_ADEC_K 2 // Kの小数点の位置

int main()
{
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;

    int m_seq = 1// M系列の値
    int i;
    int xor_shift;

    BITMAPFILEHEADER bmpfhr; // BMPファイルのファイルヘッダ(for Read)
    BITMAPINFOHEADER bmpihr; // BMPファイルのINFOヘッダ(for Read)
    FILE *fbmpr, *fbmpw;
    int *rd_bmp, *hw_usmd;
    int blue, green, red;

    k_fixed_td k_fixed;

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

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

    // rd_bmp にBMPのピクセルを代入。その際に、行を逆転する必要がある
    for (int y=0; y<bmpihr.biHeight; y++){
        for (int x=0; x<bmpihr.biWidth; x++){
            blue = fgetc(fbmpr);
            green = fgetc(fbmpr);
            red = fgetc(fbmpr);
            rd_bmp[((bmpihr.biHeight-1)-y)*bmpihr.biWidth+x] = (blue & 0xff) | ((green & 0xff)<<8) | ((red & 0xff)<<16);
        }
    }
    fclose(fbmpr);

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
           pix.user = 0;
         pix.data = i;
        ins << pix;
    }

    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            pix.data = (ap_int<32>)rd_bmp[(j*bmpihr.biWidth)+i];

            if (j==0 && i==0)    // 最初のデータの時に TUSER を 1 にする
                pix.user = 1;
            else
                pix.user = 0;

            if (i == bmpihr.biWidth-1// 行の最後でTLASTをアサートする
                pix.last = 1;
            else
                pix.last = 0;

            ins << pix;
            ins_soft << pix;
        }
    }

    int usm_k = (int)(K * pow(2.0, (double)NUM_ADEC_K));
    k_fixed = K;
    unsharp_mask_axis(1, k_fixed, ins, outs);
    unsharp_mask_axis_soft(1, usm_k, ins_soft, outs_soft, bmpihr.biWidth, bmpihr.biHeight); // k = 2;

    // ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
    cout << endl;
    cout << "outs" << endl;
    for(int j=0; j < bmpihr.biHeight; j++){
        for(i=0; i < bmpihr.biWidth; i++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;

            hw_usmd[(j*bmpihr.biWidth)+i] = (int)val;

            if (val != val_soft){
                printf("ERROR HW and SW results mismatch i = %ld, j = %ld, HW = %d, SW = %d\n", i, j, (int)val, (int)val_soft);
                //return(1);
            }
            if (vals.last)
                cout << "AXI-Stream is end" << endl;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ハードウェアのラプラシアンフィルタの結果を temp_usm.bmp へ出力する
    if ((fbmpw=fopen("temp_usm.bmp""wb")) == NULL){
        fprintf(stderr, "Can't open temp_usm.bmp by binary write mode\n");
        exit(1);
    }
    // BMPファイルヘッダの書き込み
    fwrite(&bmpfhr.bfType, sizeof(char), 2, fbmpw);
    fwrite(&bmpfhr.bfSize, sizeof(long), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved1, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfReserved2, sizeof(short), 1, fbmpw);
    fwrite(&bmpfhr.bfOffBits, sizeof(long), 1, fbmpw);
    fwrite(&bmpihr, sizeof(BITMAPINFOHEADER), 1, fbmpw);

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

            fputc(blue, fbmpw);
            fputc(green, fbmpw);
            fputc(red, fbmpw);
        }
    }
    fclose(fbmpw);
    free(rd_bmp);
    free(hw_usmd);

    return 0;
}

int unsharp_mask_axis_soft(ap_uint<1> usm_fil_enable, ap_uint<4> usm_fil_k, hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs, int width, int height){
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> usm;
    int **line_buf;
    int pix_mat[3][3];
    int usm_fil_val;
    int i;

    // line_buf の1次元目の配列をアロケートする
    if ((line_buf =(int **)malloc(sizeof(int *) * 2)) == NULL){
        fprintf(stderr, "Can't allocate line_buf[3][]\n");
        exit(1);
    }

    // メモリをアロケートする
    for (i=0; i<2; i++){
        if ((line_buf[i]=(int *)malloc(sizeof(int) * width)) == NULL){
            fprintf(stderr, "Can't allocate line_buf[%d]\n", i);
            exit(1);
        }
    }

    do {    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    for (int y=0; y<height; y++){
        for (int x=0; x<width; x++){
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix; // AXI4-Stream からの入力

            for (int k=0; k<3; k++){
                for (int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];

            pix_mat[2][2] = pix.data;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = pix.data;

            usm.data = unsharp_masking_soft(pix_mat, (int)usm_fil_k, 2);

            if (x<2 || y<2// 最初の2行とその他の行の最初の2列は無効データなので元のデータとする
                usm.data = pix.data;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                usm.user = 1;
            else
                usm.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                usm.last = 1;
            else
                usm.last = 0;

            if (usm_fil_enable)
                outs << usm;    // AXI4-Stream へ出力
            else
                outs << pix;    // 入力画像をそのまま出力
        }
    }

    for (i=0; i<2; i++)
        free(line_buf[i]);
    free(line_buf);

    return 0;
}

// アンシャープマスキング・フィルタ
// x0y0 x1y0 x2y0 -k   -j  -k
// x0y1 x1y1 x2y1 -k  9+8k -k x 1/9
// x0y2 x1y2 x2y2 -k   -k  -k
//
// k : 鮮鋭化の強さ(固定小数点)
// num_adec_k : Kの小数点の位置
//
int unsharp_masking_soft(int pix_mat[3][3], int k, int num_adec_k)
{
    float y;
    int xy[3][3];
    float rgb[3];
    int result=0;

    float fk = (float)k;
    for (int m=0; m<num_adec_k; m++){ // 小数点の位置を正しい位置にする
        fk /= 2.0;
    }

    for (int i=0; i<=16; i += 8){
        for (int j=0; j<3; j++){
            for (int k=0; k<3; k++){
                xy[j][k] = (pix_mat[j][k] >> i) & 0xff; // RGBのいずれかを抽出
            }
        }
        y = -(float)xy[0][0]         -(float)xy[0][1]      -(float)xy[0][2]
            -(float)xy[1][0] +(9.0/fk+8.0)*(float)xy[1][1] -(float)xy[1][2]
            -(float)xy[2][0]         -(float)xy[2][1]      -(float)xy[2][2];
        y = (fk * y)/9.0;

        int z = (int)(y + 0.5); // 四捨五入

        if (z<0// 飽和演算
            z = 0;
        else if (z>255)
            z = 255;

        result += z<<i; // i=0 : blue, i=8 : green, i=16 : red
    }

    return(result);
}


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

DSF2015 C-6 でのVivado HLS で生成したAXI4-Master IPの簡単な例について

DSF2015C-6 ”Xilinx社のFPGAにおける高位合成ツールVivado HLSの効果と性能”で説明したAXI4 Masterインターフェースの例をブログで説明したいと思います。

最初に GitHub のmarsee101/multi_axim にVivado HLS 2014.4 のプロジェクトがあります。これを git の clone でも zip ファイルでダウンロードでも良いので、自分のパソコンにダウンロードして下さい。
zip ファイルでダウンロードの例を説明します。
Download.zip ボタンをクリックすると保存ダイアログが開いて、multi_axim-master.zip をダウンロードすることができます。
multi_axim_1_150928.png

multi_axim-master.zip を展開すると、multi_axim-master フォルダが出てきます。これが、Vivado HLS 2014.4 のプロジェクト・フォルダです。
multi_axim-master フォルダに入ると、multi_aixm.c, multi_axim_tb.c, solution1 フォルダがあります。他のファイルやフォルダもあります。
multi_axim_2_150928.png

multi_aixm.c がハードウェアにするC ソフトウェアです。
multi_aixm_tb.c がハードウェアにするC ソフトウェア用のテストベンチです。
ファイルを開いて見てみましょう。

multi_aixm.c は、x[10] の配列の1つの要素とその要素を+1 した数の積を取って、y[10] の配列の要素に代入します。それを10個要素それぞれに付いて行います。
関数の引数で、値渡しの引数は入力ポートになります。ポインタ渡しの引数は入力ポートにも出力ポートもなります。または出力ポートと入力ポート両方を生成することもできます。
#pragma HLS INTERFACE m_axi port=y depth=10 offset=slave このディレクティブで y はAXI4 Master インターフェースになります。offset=slave はAXI4 Lite Slave インターフェースのレジスタとしてオフセットレジスがマップされます。
x も同様です。
#pragma HLS INTERFACE s_axilite port=return はブロックレベルのインターフェースを AXI4 Lite Slave にするというディレクティブになります。
動作は、x[]のアドレスでAXI4 Master Read を行って、演算してから y[] のアドレスに結果を AXI4 Master Write します。

multi_aixm_tb.c は見ればひと目でわかると思います。

solution フォルダの下にCシミュレーションの結果(csim フォルダ)、CからHDL への合成結果(syn フォルダ)、C/RTL協調シミュレーション結果(sim フォルダ)、IP化の結果(impl フォルダ)が入っています。
multi_axim_3_150928.png

multi_axim-master\solution1\csim\report フォルダに multi_axim_csim.log があるので見てましょう。(Vivado HLS をインストールしていない人向けに書いてありますので、持ってい方はVivado HLS で csim のリポートを見れば同じです)
Cシミュレーションの結果が、multi_axim_csim.log に書いてあります。
multi_axim_4_150928.png

multi_axim-master\solution1\syn フォルダには、C からHDL へ合成した結果が入っています。
report フォルダは合成結果が入っています。
systemc, verilog, vhdl フォルダには、合成した結果のHDL が入っています。
multi_axim_5_150929.png

report フォルダを見てみましょう。
multi_axim_csynth.rpt を開いてみてください。
multi_axim_csynth.rpt にはCからHDL への合成時のレポートが入っています。
Timing Summary の Target 10.00 の単位は ns でターゲットの動作周期です。
Estimated が合成によって推定された動作周期です。これが 8.75 ns です。
Latency と Interval も見て下さい。
multi_axim_6_150929.png

次に、verilog フォルダを開いてみてください。
ファイルが4つありますが、multi_axim.v がトップなので開いてみてください。
multi_axim_7_150929.png
s_axi_AXILiteS_... がAXI4 Lite Slave インターフェースの信号
m_axi_gmem_... がAXI4 Master インターフェースの信号です。

multi_axim_AXILiteS_s_axi.v を開いてみてください。
45行目から Address Info が書いてあります。これが、AXI4 Lite Slave のアドレスマップです。
Data signal of x が x[] 配列のオフセット・アドレス用レジスタです。ここに x[] 配列があるアドレスをセットします。
Data signal of y が y[] 配列のオフセット・アドレス用レジスタです。ここに y[] 配列があるアドレスをセットします。
multi_axim_8_150929.png

0x00 : Control signals の bit 0 - ap_start に 1 を書くと、このIP の処理が始まります。bit 1 - ap_done が 1 になるとIP の処理が終了しています。

残りのファイルを見て下さい。

solution1 フォルダに戻って、次は sim フォルダに入ります。
multi_axim_9_150930.png

sim フォルダの中の verilog フォルダに入ります。
multi_axim_10_150930.png

ここに、multi_axim.wdb と multi_axim.wcfg があるので、これをVivado のTcl Console から開いてRTL シミュレーション波形を確認します。

Vivado を持っていたら、Vivado を起動します。
multi_axim_11_150930.png

フォルダを cd コマンドで移動します。私の環境では、

cd c:/Users/Masaaki/Documents/Vivado_HLS/ZYBO/examples/multi_axim-master/solution1/sim/verilog

ですが、自分の環境の multi_axim-master/solution1/sim/verilog フォルダに移動して下さい。コマンドを入れるとフォルダの選択肢をTcl Console が表示してくれます。
multi_axim_12_150930.png

続けて

current_fileset
open_wave_database multi_axim.wdb
open_wave_config multi_axim.wcfg

をTcl Console に入力します。3つのコマンドをコピー&ペーストしても問題無いです。
そうすると波形が表示されます。
multi_axim_13_150930.png

波形をじっくりご覧下さい。

AXI4 Lite Slave, AXI4 MASTER Write 部分の波形を下に示します。
multi_axim_14_150930.png

AXI4 MASTER Write 部分を引き伸ばしてみると、y[] 配列に書き込んでいるデータ(m_axi_gmem_WDATA[31:0] が見えます。
multi_axim_15_150930.png

AXI4 Master Read と AXI4 MASTER Write を一緒に見てみましょう。
multi_axim_16_150930.png

最後にIP 化した部分を説明します。

solution1 フォルダに戻って、impl フォルダに入ります。
multi_axim_17_150930.png

更に、ip フォルダに入って下さい。ここがIP のフォルダです。
multi_axim_18_150930.png

drivers -> multi_axim_v1_0 -> src フォルダがドライバのソースファイルです。
multi_axim_19_150930.png

例えば、multi_axim.c を開いてみましょう。
multi_axim_20_150930.png

ここにドライバの関数が並んでいます。
例えば、XMulti_axim_Start() はIP の処理を開始させる関数です。

Vivado HLSの生成したドライバの使い方です。

  • 最初にX<関数名>_Initialize()、またはX<関数名>_LookupConfig()X<関数名>_CfgInitialize()の組
    • ベアメタル・アプリのDeviceIdは最初のインスタンスは0、次は1
  • X<関数名>_Set_入力ポートで入力ポートの値をWriteする
  • X<関数名>_IsIdleでアイドル状態であることを確認
  • X<関数名>_StartでIPのステートマシンをスタート
  • X<関数名>_IsDoneX<関数名>_出力ポート_vldを確認
  • X<関数名>_Get_出力ポートをReadする

いろいろとC ソースファイルを読んでみると面白いです。
ベアメタル・アプリケーションでは、SDKからこれらの関数を使うことができます。
LinuxではUIO でドライバを使うことができますが、デバイス・ツリーに登録する必要があります。

ip フォルダのxilinx_com_hls_multi_axim_1_0.zip がIP を圧縮したファイルになります。中身を下に示します。
multi_axim_21_150930.png

これで、DSF2015C-6 ”Xilinx社のFPGAにおける高位合成ツールVivado HLSの効果と性能”で説明したAXI4 Masterインターフェースの例の説明を終わります。
  1. 2015年10月02日 14:40 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS によるアンシャープマスクキング・フィルタの作製6(実機確認)

Vivado HLS によるアンシャープマスクキング・フィルタの作製5(Vivado プロジェクトの作製)”の続き。

前回はVivado 2015.2 のブロックデザインを作製し、アンシャープマスキング・フィルタIP をHDMI 入力 - HDMI 出力のAXI4 Stream 間に挿入した。
今回は、制約ファイルを作製してから、プロジェクトを論理合成、インプリメント、ビットストリームの生成を行って、実機で検証する。

最初に、ラプラシアンフィルタIP の時の制約ファイル(dvi2vga.xdc)をプロジェクトに追加した。
SW0 の配置制約はとりあえず削除した。
unsharp_mask_34_150929.png

Synthesized Design を開いて、Package を表示した。
sw[3:0] をSite を割り当てた。I/O Std は LVCOMS33 に設定した。
unsharp_mask_35_150929.png

追加した SW[3:0] の制約ファイルを下に示す。
unsharp_mask_36_150930.png

dvi2vga.xdc を下に示す。

set_property PACKAGE_PIN P20 [get_ports {vga_pBlue[0]}]
set_property PACKAGE_PIN M20 [get_ports {vga_pBlue[1]}]
set_property PACKAGE_PIN K19 [get_ports {vga_pBlue[2]}]
set_property PACKAGE_PIN J18 [get_ports {vga_pBlue[3]}]
set_property PACKAGE_PIN G19 [get_ports {vga_pBlue[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pBlue[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pBlue[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pBlue[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pBlue[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pBlue[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pGreen[0]}]
set_property PACKAGE_PIN H18 [get_ports {vga_pGreen[0]}]
set_property PACKAGE_PIN N20 [get_ports {vga_pGreen[1]}]
set_property PACKAGE_PIN L19 [get_ports {vga_pGreen[2]}]
set_property PACKAGE_PIN J19 [get_ports {vga_pGreen[3]}]
set_property PACKAGE_PIN H20 [get_ports {vga_pGreen[4]}]
set_property PACKAGE_PIN F20 [get_ports {vga_pGreen[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pRed[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pRed[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pRed[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pRed[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_pRed[0]}]
set_property PACKAGE_PIN M19 [get_ports {vga_pRed[0]}]
set_property PACKAGE_PIN L20 [get_ports {vga_pRed[1]}]
set_property PACKAGE_PIN J20 [get_ports {vga_pRed[2]}]
set_property PACKAGE_PIN G20 [get_ports {vga_pRed[3]}]
set_property PACKAGE_PIN F19 [get_ports {vga_pRed[4]}]
set_property PACKAGE_PIN H16 [get_ports TMDS_Clk_p]
set_property PACKAGE_PIN D19 [get_ports {TMDS_Data_p[0]}]
set_property PACKAGE_PIN C20 [get_ports {TMDS_Data_p[1]}]
set_property PACKAGE_PIN B19 [get_ports {TMDS_Data_p[2]}]
set_property PACKAGE_PIN G18 [get_ports ddc_sda_io]
set_property PACKAGE_PIN G17 [get_ports ddc_scl_io]
set_property PACKAGE_PIN P19 [get_ports vga_pHSync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_pHSync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_pVSync]
set_property PACKAGE_PIN R19 [get_ports vga_pVSync]
set_property PACKAGE_PIN L16 [get_ports clk125]
#set_property PACKAGE_PIN R18 [get_ports reset]
#set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property IOSTANDARD LVCMOS33 [get_ports clk125]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports ddc_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_hpd[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN E18 [get_ports {hdmi_hpd[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]

set_property PACKAGE_PIN G15 [get_ports {sw[0]}]
set_property PACKAGE_PIN P15 [get_ports {sw[1]}]
set_property PACKAGE_PIN W13 [get_ports {sw[2]}]
set_property PACKAGE_PIN T16 [get_ports {sw[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[0]}]


論理合成、インプリメント、ビットストリームの生成を行って成功した。
unsharp_mask_37_150930.png

Project Summary を示す。
unsharp_mask_41_151001.png

ZYBO を使って実機で検証した。下に表示した画面を示す。
unsharp_mask_40_151001.jpg

paint.net で ガウスボケを半径 1.5 をかけた画像を示す。これが元画像だ。
unsharp_mask_38_151001.jpg

アンシャープマスキング・フィルタ k= 3.5 をかけた画像を下に示す。文字の輪郭がシャープになっている。
unsharp_mask_39_151001.jpg

写真をとった位置が違っているので、文字の大きさが異なり、比較が難しいかもしれないが、アンシャープマスキング・フィルタ k= 3.5 をかけた画像の方が元画像より文字がくっきり見えているのがわかると思う。
  1. 2015年10月01日 04:00 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0