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

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

FPGAの部屋

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

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

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/3290-ccc86faa
この記事にトラックバックする(FC2ブログユーザー)