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

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

FPGAの部屋

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

”スター・ウォーズ/フォースの覚醒”を見てきました

今日は、午前10時から奥さんと息子と3人で”スター・ウォーズ/フォースの覚醒”を見てきました。
懐かしいキャラが3人も出てきて懐かしかったです。スター・ウォーズは大学2年の時にエピソード4 を映画館で見て以来のファンです。新作が出てとっても嬉しいです。よりリアルにスター・ウォーズの世界を堪能できました。エピソード8 が楽しみです。
  1. 2015年12月20日 10:54 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLSでクロック周期を2.5ns で合成した掛け算回路は本当に400MHzで動作するのか?

SlideShare で公開している”Vivado hls勉強会2(レジスタの挿入とpipelineディレクティブ)”の 70 ページの Solution から Vivado HLS でクロック周期が 2.5 ns つまり 400 MHz で動作するように設定して高位合成を行っているのだが、本当に400 MHz で動作するのか?をVivado 2015.4 でプロジェクトを作製してテストしてみた。

Vivado HLS 2015.4 で multi_apuint.cpp をSolution の Synthesis Settings -> Clock Period 2.5 ns (400 MHz) で合成した。
なお、公開したコードからでは、ブロックのインターフェースを ap_ctrl_none に変更している。使用するFPGAはZYBO で使用している xc7z010clg400-1 に設定した。
multi_apuint_1_151220.png

合成後のレポート。 2.15 ns (465 MHz) 動作するとのことだ。
multi_apuint_7_151220.png

これをIP化を行った。

次に、Vivado 2015.4を起動して、multi_apint プロジェクトを作製した。

Vivado HLS 2015.4 で作製したIP をIP Catalog にインポートして、multi_apuint_bd ブロックデザインを生成した。

ブロックデザインに、multi_apuint IP をAdd IP し、外部ポートを接続した。
multi_apuint_3_151220.png

ラッパーHDL を作製して、論理合成を行った。

multi_apuint_bd.xdc を作製して、2.5 ns のタイミング制約を追加した。
multi_apuint_4_151220.png

create_clock -period 2.500 -name multi_clk -waveform {0.000 1.250} ap_clk


インプリメントを行った。ビットストリームの生成はIOピンを指定していないためエラーだった。
multi_apuint_5_151220.png

タイミング制約も満たされている。
multi_apuint_6_151220.png

Implemented Design を開いて、Timing Summary を見ると、2.5 ns のクロック周期制約は満たされていて、最大のクロック周期は 1.671 ns だった、これは、598.4 MHz に相当する。
multi_apuint_2_151220.png

凄いことだ。ZYBOで掛け算回路が約 600 MHz で動作するように出来たのだから。。。
Vivado HLS の凄い所は、同じC, C++ ソースコードが、100 MHzで動作するようにも合成できたり、約 600 MHz でも動作するようにも合成できることだと思う。それぞれ、リソース使用量とレイテンシは違うが、PIPELINEディレクティブを入れて、完全にパイプラインできていれば、1クロックで掛け算が終了することには変わりがない。ということは、600 MHz で動作する掛け算回路は、100 MHz で動作する掛け算回路よりも 6 倍のスループットがある訳だ。それを、設定1発で変更できるのは凄いことだと思う。

(追記)
どうやら4ステージのパイプラインはすべてDSP48E1で実現されているようだ。それで、約 600 MHzという動作周波数が実現できたようだ。FF と LUT で実現されている訳ではない。
multi_apuint_8_151220.png

それでも、DSP48E1がパイプラインできるって知らなかったし、Vivado HLSが合成してくれて初めて使えたことを思うと、とっても良いと思う。だから、もっと複雑な回路は400 MHzとかの動作周波数では動かないはずだと思う。但し、動作周波数を変更できるのは、とっても良いと思う。
  1. 2015年12月20日 07:05 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラのReport CDC unsafe 箇所を確認し、修正する

Vivado のImplemented Design で Report CDC を確認する”で確認されたビットマップ・ディスプレイ・コントローラのReport CDC unsafe 箇所を確認して修正してみよう。

From は ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/cs_rdg_reg[0]/C
To は ZYBO_1_XGA_test_i/bitmap_disp_cntrler_axi_master_0/inst/bitmap_disp_eng_inst/hv_cnt_ena_d1_reg/D
だった。

bitmap_disp_eng.v でのFrom 部分を下に示す。

    // Readデータ処理モジュール用ステートマシン
    always @(posedge clk_axi) begin
        if (reset_axi)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    if (ddr_cont_init_done)
                        cs_rdg <= init_full_mode;
                init_full_mode : // 最初にcam_data_afifo をFULLにするステート、このステートではVGA信号は出力しないで、ひたすらcam_data_afifo がFULLになるのを待つ。
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
                wait_half_full : // cam_data_afifo がHALF_FULLになるまでこのステートで待機
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (wr_data_count<=AFIFO_HALF_FULL_VAL)
                        cs_rdg <= req_burst;
                req_burst :
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (read_count==0) // データが全部来たら
                        cs_rdg <= wait_half_full;
                frame_wait_state : // 1フレーム終了後vsync の時にWaitする
                    if (vsyncx_rise_pulse) // vsyncx の立ち上がり
                        cs_rdg <= frame_start_full;
                frame_start_full : // 1フレームのスタートの時にFIFOをフルにする
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
            endcase
        end
    end
    assign hv_count_enable = (cs_rdg==wait_half_full || cs_rdg==req_burst || cs_rdg==frame_wait_state || cs_rdg==frame_start_full) ? 1'b1 : 1'b0;


リセット後ビットマップ・ディスプレイ・コントローラがスタートする時に、画像データ用FIFO を画像データで満たしてから水平カウンタ、垂直カウンタを始動しようと思っていて、そのためのイネーブル信号 (hv_count_enable) を生成している。 hv_count_enable は組み合わせ回路で作っている。 hv_count_enable はリセット後画像データ用FIFO が満たされるまでは 0 で、フルになった時に 1 になって、その後はずーと 1 だ。

この、hv_count_enable はピクセルクロックで動作する水平カウンタ、垂直カウンタにイネーブル信号として入力するために FF 2個を使用したシンクロナイザーを通してある。その後、水平カウンタ、垂直カウンタにイネーブル信号として入ってる。

    // h_count、v_count用にclk_axi 動作のcs_rdg の値を使用するので2回clk_disp 動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            hv_cnt_ena_d1 <= 1'b0;
            hv_cnt_ena_d2 <= 1'b0;
        end else begin
            hv_cnt_ena_d1 <= hv_count_enable;
            hv_cnt_ena_d2 <= hv_cnt_ena_d1;
        end
    end

    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
            h_count <= h_count + 1;
    end

    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            v_count <= 0;
        else if (h_count>=(H_SUM-1)) begin // 水平カウンタがクリアされるとき
            if (v_count>=(V_SUM-1)) // v_count がV_SUM-1よりも大きければ0に戻す(mode V_SUM)
                v_count <= 0;
            else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
                v_count <= v_count + 1;
        end
    end


よって、この信号が unsafe だとしても問題は無いと思うのだが、修正を試みてみよう。

Verilog HDL コードをこのまま修正することは容易だが、Vivado の修正を認知させるために、IP Integrator のブロックデザインの ZYBO_1_XGA_test を開いて、bitmap_disp_cntrler_axi_master_0 を IP Packager を起動して修正する。
ZYBO_1_XGA_test_48_151220.png

組み合わせ回路の出力を hv_count_ena_comb に変更して、それをFF に通して hv_count_enable 信号として出力した。

    assign hv_count_ena_comb = (cs_rdg==wait_half_full || cs_rdg==req_burst || cs_rdg==frame_wait_state || cs_rdg==frame_start_full) ? 1'b1 : 1'b0;
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            hv_count_enable <= 1'b0;
        end else begin
            hv_count_enable <= hv_count_ena_comb;
        end
    end


これで、再度パッケージ化を行った。
ZYBO_1_XGA_test_49_151220.png

また、ZYBO_1_XGA_test プロジェクトに戻って、論理合成、インプリメント、ビットストリームの生成を行った。タイミングも満足して成功した。
Implemented Design を開いて、Tools -> Timing -> Report DRC... を実行した。
ZYBO_1_XGA_test_50_151220.png

Unsafe が消えて、問題が無くなった。
修正を行ったが、たぶん、動作は前と変わっていないと思う。
  1. 2015年12月20日 05:02 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0