FC2カウンター FPGAの部屋 2019年01月18日
FC2ブログ

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

FPGAの部屋

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

Ultra96のDisplayPortを使用するためのIPを作成する6(テストベンチ の作成2)

Ultra96のDisplayPortを使用するためのIPを作成する5(テストベンチ の作成1)”の続き。

前回は、テストベンチを作成する1歩として、 pattern_gen_axis をテストベンチに使用するために修正した。今回は、テストベンチ本体を作成してテストを行う。

(2019/01/21:追記)dp_video_out_hsync とdp_video_out_vsync の極性をアクティブローとしてVerilog HDL を作成しましたが、実際はアクティブハイのためこのVerilog HDL コードは動作しません。
詳しくは、”Ultra96のDisplayPortを使用するためのIPを作成する7(テストベンチ の作成3)”をご覧ください。

まずは、axis2video_out.v を貼っておく。

// axis2video_out.v
// 2019/01/14 by marsee
//

`default_nettype none

module axis2video_out
    (
        // Clock and Reset
        input wire  disp_clk,
        input wire  axi_clk,
        input wire  axi_rst_n,
        input wire  init_done,
        
        // AXI4-Stream
        input wire  [31:0] axis_tdata,
        input wire  axis_tvalid,
        output wire axis_tready,
        input wire  [3:0] axis_tkeep,
        input wire  [3:0] axis_tstrb,
        input wire  axis_tuser,
        input wire  axis_tlast,
        input wire  axis_tid,
        input wire  axis_tdest,
        
        // IP
        output reg  ip_start,
        input wire  ip_done,
        
        // video in
        input wire  de_in,
        input wire  vsync_in,
        input wire  hsync_in,
        
        // video_out
        output wire  [35:0] disp_pixel,
        output wire  de_out,
        output wire vsync_out,
        output wire  hsync_out
    );

    parameter       IDLE_START =    1'b0,
                    IP_START_1 =    1'b1;
    
    reg     reset_disp_2b = 1'b1, reset_disp_1b = 1'b1;
    wire    reset_disp;
    reg     fifo_reset_axi_2b = 1'b0, fifo_reset_axi_1b = 1'b0;
    wire    fifo_reset_axi;
    reg     fifo_reset_disp_2b = 1'b0, fifo_reset_disp_1b = 1'b0;
    wire    fifo_reset_disp;
    reg     de_1d, vsync_1d, hsync_1d;
    reg     vsync_axi_1b, vsync_axi_2b;
    wire    vsync_axi;
    reg     vsync_axi_1d, vsync_axi_2d;
    reg     cs_start;
    wire    pfifo_empty, pfifo_full;
    wire [31:0] pfifo_dout;
    reg    vsync_rising_edge_axi, vsync_falling_edge_axi;
    
    always @(posedge disp_clk) begin
        if(reset_disp) begin
            de_1d <= 1'b0;
            vsync_1d <= 1'b1;
            hsync_1d <= 1'b1;
        end else begin
            de_1d <= de_in;
            vsync_1d <= vsync_in;
            hsync_1d <= hsync_in;
        end
    end
    
    // reset signals    
    always @(posedge axi_clk) begin
        fifo_reset_axi_2b <= ~init_done | ~axi_rst_n | ~vsync_1d;
        fifo_reset_axi_1b <= fifo_reset_axi_2b;
    end
    assign fifo_reset_axi = fifo_reset_axi_1b;
        
    always @(posedge disp_clk) begin
        fifo_reset_disp_2b <= ~init_done | ~axi_rst_n | ~vsync_1d;
        fifo_reset_disp_1b <= fifo_reset_disp_2b;
    end
    assign fifo_reset_disp = fifo_reset_disp_1b;
        
    always @(posedge disp_clk) begin
        reset_disp_2b <= ~init_done | ~axi_rst_n;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;
    
    // vsync_rising_edge, vsync_falling_edge
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_axi_2b <= 1'b1;
            vsync_axi_1b <= 1'b1;
        end else begin
            vsync_axi_2b <= vsync_1d;
            vsync_axi_1b <= vsync_axi_2b;
        end
    end
    assign vsync_axi = vsync_axi_1b;
    
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_axi_1d <= 1'b1;
            vsync_axi_2d <= 1'b1;
        end else begin
            vsync_axi_1d <= vsync_axi;
            vsync_axi_2d <= vsync_axi_1d;
        end
    end

    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            vsync_rising_edge_axi = 1'b0;
            vsync_falling_edge_axi = 1'b0;
        end else begin
            vsync_rising_edge_axi <= ~vsync_axi_2d & vsync_axi_1d;
            vsync_falling_edge_axi <= vsync_axi_2d & ~vsync_axi_1d;
        end
    end
    
    // IP start State Machine
    always @(posedge axi_clk) begin
        if (!axi_rst_n) begin
            cs_start <= IDLE_START;
            ip_start <= 1'b0;
        end else begin
            case (cs_start)
                IDLE_START : begin
                    ip_start <= 1'b0;
                    if (vsync_rising_edge_axi)
                        cs_start <= IP_START_1;
                end
                IP_START_1 : begin
                    ip_start <= 1'b1;
                    if (ip_done)
                        cs_start <= IDLE_START;
                end
            endcase
        end
    end
    
    // data width 34 bits, 512 depth
    pixel_fifo pixel_fifo_i (
        .wr_rst(fifo_reset_axi),
        .wr_clk(axi_clk),
        .rd_rst(fifo_reset_disp),
        .rd_clk(disp_clk),
        .din({axis_tuser, axis_tlast, axis_tdata}),
        .dout(pfifo_dout),
        .wr_en(~pfifo_full & axis_tvalid),
        .full(pfifo_full),
        .rd_en(de_1d),
        .empty(pfifo_empty)
    );
    assign axis_tready = ~pfifo_full;
    
    assign disp_pixel = {pfifo_dout[23:16], 4'd0, pfifo_dout[15:8], 4'd0, pfifo_dout[7:0], 4'd0};
    assign de_out = de_1d;
    assign vsync_out = vsync_1d;
    assign hsync_out = hsync_1d;
endmodule

`default_nettype wire


次に、テストベンチのaxis2video_out_tb.v を貼っておく。

`default_nettype none
`timescale 100ps / 1ps

// axis2video_out_tb.v
// 2019/01/17 by marsee
//

module axis2video_out_tb;

    reg  axi_clk;
    reg  axi_rst_n;
    wire ip_start;
    wire ip_done;
    wire [31:0] TDATA;
    wire TVALID;
    wire TREADY;
    wire [3:0] TKEEP;
    wire [3:0] TSTRB;
    wire TUSER;
    wire TLAST;
    wire TID;
    wire TDEST;
    reg  init_done;
    wire init_done_out;
    reg  disp_clk;
    reg  de_in;
    reg  vsync_in;
    reg  hsync_in;
    wire [35:0] disp_pixel;
    wire de_out;
    wire vsync_out;
    wire hsync_out;
    
    // pattern_gen_axis instance
    pattern_gen_axis pga_inst(
        .ap_clk(axi_clk),
        .ap_rst_n(axi_rst_n),
        .ap_start(ip_start),
        .ap_done(ip_done),
        .ap_idle(),
        .ap_ready(),
        .outs_TDATA(TDATA),
        .outs_TVALID(TVALID),
        .outs_TREADY(TREADY),
        .outs_TKEEP(TKEEP),
        .outs_TSTRB(TSTRB),
        .outs_TUSER(TUSER),
        .outs_TLAST(TLAST),
        .outs_TID(TID),
        .outs_TDEST(TDEST),
        .init_done_V(init_done),
        .init_done_out_V(init_done_out),
        .ap_return()
    );
    
    // axis2video_out instance
    axis2video_out axis2vo_inst(
        .disp_clk(disp_clk),
        .axi_clk(axi_clk),
        .axi_rst_n(axi_rst_n),
        .init_done(init_done),
        .axis_tdata(TDATA),
        .axis_tvalid(TVALID),
        .axis_tready(TREADY),
        .axis_tkeep(TKEEP),
        .axis_tstrb(TSTRB),
        .axis_tuser(TUSER),
        .axis_tlast(TLAST),
        .axis_tid(TID),
        .axis_tdest(TDEST),
        .ip_start(ip_start),
        .ip_done(ip_done),
        .de_in(de_in),
        .vsync_in(vsync_in),
        .hsync_in(hsync_in),
        .disp_pixel(disp_pixel),
        .de_out(de_out),
        .vsync_out(vsync_out),
        .hsync_out(hsync_out)
    );
    
    // axi_clk = 200 MHz (5 ns)
    always #25
        axi_clk = ~axi_clk;
    
    // disp_clk = 65 MHz (13.4 ns)
    always #77
        disp_clk = ~disp_clk;
        
    initial  begin
        axi_clk = 1'b1;
        disp_clk = 1'b1;
        axi_rst_n = 1'b0;
        init_done = 1'b0;
        de_in = 1'b0;
        vsync_in = 1'b1;
        hsync_in = 1'b1;

        // Wait 100 ns for global reset to finish
        #1000;
        axi_rst_n = 1'b1;
        
        #500;
        init_done = 1'b1;
        
        #1000;
        vsync_in = 1'b0;
        
        #1000;
        vsync_in = 1'b1;
        
        #1000;
        de_in = 1'b1;
        
        #5000;
        de_in = 1'b0;
        
        #1000;
        hsync_in = 1'b0;
        
        #1000;
        hsync_in = 1'b1;
    end
endmodule

`default_nettype wire


Vivado 2018.3 のaxis2video_out プロジェクトを示す。
DisplayPort_test_77_190117.png

論理シミュレーションを行った。
DisplayPort_test_78_190117.png

あまり検証していないが、大丈夫そうだろう?実機で確認しよう。

Tools メニューからCreate and Package New IP... を選択してIP にする。
ダイアログで適当に選ぶと、Package IP タブが表示された。
DisplayPort_test_79_190117.png

Package Steps のCustomization GUI
DisplayPort_test_80_190117.png

Package Steps のReview and Package で、Edit packaging settings をクリックする。表示されたSetings ダイアログで、Create archive of IP にチェックが入っていることを確認する。
Package IP ボタンをクリックする。
DisplayPort_test_81_190117.png

axis2video_out がIP になった。
DisplayPort_test_82_190118.png

axis2video_out ディレクトリにuser.org_user_axis2video_out_1.0.zip ができた。
DisplayPort_test_83_190118.png
  1. 2019年01月18日 04:08 |
  2. Ultra96
  3. | トラックバック:0
  4. | コメント:0