FC2カウンター FPGAの部屋 Triple Frame Buffer Controller の追加3(単体シミュレーション)

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

FPGAの部屋

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

Triple Frame Buffer Controller の追加3(単体シミュレーション)

前回、”Triple Frame Buffer Controller の追加2(ポートの追加)”では、カメラ・インターフェイスIPとビットマップ・ディスプレイ・コントローラIPを書き換えてポートを追加した。
今回は、HDLファイルを書いて、単体でシミュレーションを行った。書いたVerilog HDLファイルは、triple_fb_state.v、triple_fb_cntrler.v、それにテストベンチの triple_tb_cntrler_tb.v だ。

早速、シミュレーション波形を見ていこう。下に示すのが、Writeつまりカメラのフレームレートが 15fps で、Readつまり、ディスプレイのフレームレートが 60fps の場合だ。
Triple_FBC_6_130510.png

camera_fb_start_addr と bitmapd_fb_start_addr を見ると、フレームバッファ1、フレームバッファ2、フレームバッファ3のアドレスを順番に表示していて、しかも2つのアドレスが競合しないのが分かる。

順番が逆になったが、Project Navigator の画面を下に示す。
Triple_FBC_7_130510.png

元の triple_tb_cntrler IP の階層では深過ぎて、ISimがエラーを出力してしまうので、階層を浅くしてシミュレーションを行なっている。(”カメラ・インターフェースIPにAXI4 Lite Slave インターフェースを追加1(ISimでエラー)”を参照)

これで単体シミュレーションは終了した。
下に、各 Verilog HDL ファイルを示す。

最初に、triple_fb_state.v

// Triple Frame Buffer State
// triple_fb_state.v
// 2013/05/09
//

`default_nettype none

module triple_fb_state (
    input    wire    clk,
    input    wire    reset,
    input    wire    write_req_p,
    input    wire    display_req_p,
    input    wire    frame_valid_p,
    input    wire    display_enable_p,
    output    reg        [1:0]    state
);
    localparam     wait_write =     2'b00,
                writing    =        2'b01,
                displaying =    2'b10,
                wait_display =    2'b11;
    
    always @(posedge clk) begin
        if (reset)
            state <= wait_write;
        else begin
            case (state)
                wait_write :
                    if (write_req_p)
                        state <= writing;
                writing :
                    if (write_req_p)
                        state <= writing;
                    else if (frame_valid_p)
                        state <= wait_display;
                wait_display :
                    if (display_req_p)
                        state <= displaying;
                displaying :
                    if (display_req_p)
                        state <= displaying;
                    else if (display_enable_p)
                        state <=wait_write;
            endcase
        end
    end
    
    // synthesis translate_off
     reg [12*8:1] FB_STATE;
     
     always @(state) begin
        case (state)
            wait_write:        FB_STATE <= "WAIT_WRITE";
            writing:        FB_STATE <= "WRITING";
            displaying :    FB_STATE <= "DISPLAYING";
            wait_display :    FB_STATE <= "WAIT_DISPLAY";
        endcase
    end    
    // synthesis translate_on
endmodule

`default_nettype wire    


次に、triple_fb_cntrler.v

// Triple Frame Buffer Controller
// triple_fb_cntrler.v
// 2013/05/09
//

`default_nettype none

module triple_fb_cntrler #(
    parameter integer C_M_AXI_ADDR_WIDTH            = 32,
    parameter [31:0]    C_DISPLAY_START_ADDRESS        = 32'h1A000000    // フレームバッファのスタートアドレス
)(
    input    wire    aclk,
    input    wire    aresetn,
    output    reg    [C_M_AXI_ADDR_WIDTH-1 :0]    camera_fb_start_addr,
    output    reg    [C_M_AXI_ADDR_WIDTH-1 :0]    bitmapd_fb_start_addr,
    input    wire    frame_valid_1d,
    input    wire    display_enable
);
    `include "./disp_timing_parameters.vh"

    localparam    wait_write =    2'b00,
                writing    =    2'b01,
                displaying =    2'b10,
                wait_display =    2'b11;
    localparam    FIRST_FB_ADDRESS =    C_DISPLAY_START_ADDRESS;
    localparam    SECOND_FB_ADDRESS =    C_DISPLAY_START_ADDRESS + (H_ACTIVE_VIDEO * V_ACTIVE_VIDEO)*4;
    localparam    THIRD_FB_ADDRESS =    SECOND_FB_ADDRESS + (H_ACTIVE_VIDEO * V_ACTIVE_VIDEO)*4;
    
    reg        fv_1d_1d, fv_1d_2d, fv_1d_3d;
    reg        de_1d, de_2d, de_3d;
    wire    reset;
    reg        fv_1d_p, de_p;
    reg        reset_1b;
    reg        write_req_p_1, write_req_p_2, write_req_p_3;
    reg        display_req_p_1, display_req_p_2, display_req_p_3;
    wire    [1:0] state_1, state_2, state_3;
    
    assign reset = ~aresetn;
    // Sychronization
    always @(posedge aclk) begin
        if (reset) begin
            fv_1d_1d <= 1'b0;
            fv_1d_2d <= 1'b0;
            fv_1d_3d <= 1'b0;
            de_1d <= 1'b0;
            de_2d <= 1'b0;
            de_3d <= 1'b0;
        end else begin
            fv_1d_1d <= frame_valid_1d;
            fv_1d_2d <= fv_1d_1d;
            fv_1d_3d <= fv_1d_2d;
            de_1d <= display_enable;
            de_2d <= de_1d;
            de_3d <= de_2d;
        end
    end
    
    always @(posedge aclk) begin
        if (reset)
            fv_1d_p <= 1'b0;
        else begin
            if (fv_1d_2d==1'b0 && fv_1d_3d==1'b1) // falling edge
                fv_1d_p <= 1'b1;
            else
                fv_1d_p <= 1'b0;
        end
    end
    
    always @(posedge aclk) begin
        if (reset)
            de_p <= 1'b0;
        else begin
            if (de_2d==1'b0 && de_3d==1'b1) // falling edge
                de_p <= 1'b1;
            else
                de_p <= 1'b0;
        end
    end
    
    always @(posedge aclk) begin
        reset_1b <= reset;
    end
    
    // write_req_p_1, write_req_p_2, write_req_p_3
    always @(posedge aclk) begin
        if (reset) begin
            write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
            camera_fb_start_addr <= FIRST_FB_ADDRESS;
        end else if (~reset & reset_1b) begin // reset falling edge
            write_req_p_1 <= 1'b1; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
        end else if (fv_1d_2d==1'b0 && fv_1d_3d==1'b1) begin // falling edge
            if (state_1 == wait_write) begin
                write_req_p_1 <= 1'b1; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
                camera_fb_start_addr <= FIRST_FB_ADDRESS;
            end else if (state_2 == wait_write) begin
                write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b1; write_req_p_3 <= 1'b0;
                camera_fb_start_addr <= SECOND_FB_ADDRESS;
            end else if (state_3 == wait_write) begin
                write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b1;
                camera_fb_start_addr <= THIRD_FB_ADDRESS;
            end else if (state_1==writing && state_2!=wait_write && state_3!=wait_write) begin
                write_req_p_1 <= 1'b1; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
                camera_fb_start_addr <= FIRST_FB_ADDRESS;
            end else if (state_2==writing && state_1!=wait_write && state_3!=wait_write) begin
                write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b1; write_req_p_3 <= 1'b0;
                camera_fb_start_addr <= SECOND_FB_ADDRESS;
            end else if (state_3==writing && state_2!=wait_write && state_3!=wait_write) begin
                write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b1;
                camera_fb_start_addr <= THIRD_FB_ADDRESS;
            end else begin
                write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
            end
        end else begin
            write_req_p_1 <= 1'b0; write_req_p_2 <= 1'b0; write_req_p_3 <= 1'b0;
        end
    end
    
    // display_req_p_1, display_req_p_2, display_req_p_3
    always @(posedge aclk) begin
        if (reset) begin
            display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b0;
            bitmapd_fb_start_addr <= FIRST_FB_ADDRESS;
        end else if (de_2d==1'b0 && de_3d==1'b1) begin // falling edge
            if (state_1 == wait_display) begin
                display_req_p_1 <= 1'b1; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b0;
                bitmapd_fb_start_addr <= FIRST_FB_ADDRESS;
            end else if (state_2 == wait_display) begin
                display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b1; display_req_p_3 <= 1'b0;
                bitmapd_fb_start_addr <= SECOND_FB_ADDRESS;
            end else if (state_3 == wait_display) begin
                display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b1;
                bitmapd_fb_start_addr <= THIRD_FB_ADDRESS;
            end else if (state_1==displaying && state_2!=wait_display && state_3!=wait_display) begin
                display_req_p_1 <= 1'b1; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b0;
                bitmapd_fb_start_addr <= FIRST_FB_ADDRESS;
            end else if (state_2==displaying && state_1!=wait_display && state_3!=wait_display) begin
                display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b1; display_req_p_3 <= 1'b0;
                bitmapd_fb_start_addr <= SECOND_FB_ADDRESS;
            end else if (state_3==displaying && state_1!=wait_display && state_2!=wait_display) begin
                display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b1;
                bitmapd_fb_start_addr <= THIRD_FB_ADDRESS;
            end else begin
                display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b0;
            end
        end else begin
            display_req_p_1 <= 1'b0; display_req_p_2 <= 1'b0; display_req_p_3 <= 1'b0;
        end
    end
    
    // First Frame Buffer State
    triple_fb_state first_fb_state (
        .clk(aclk),
        .reset(reset),
        .write_req_p(write_req_p_1),
        .display_req_p(display_req_p_1),
        .frame_valid_p(fv_1d_p),
        .display_enable_p(de_p),
        .state(state_1)
    );
    
    // Second Frame Buffer State
    triple_fb_state second_fb_state (
        .clk(aclk),
        .reset(reset),
        .write_req_p(write_req_p_2),
        .display_req_p(display_req_p_2),
        .frame_valid_p(fv_1d_p),
        .display_enable_p(de_p),
        .state(state_2)
    );

    // Third Frame Buffer State
    triple_fb_state third_fb_state (
        .clk(aclk),
        .reset(reset),
        .write_req_p(write_req_p_3),
        .display_req_p(display_req_p_3),
        .frame_valid_p(fv_1d_p),
        .display_enable_p(de_p),
        .state(state_3)
    );

    // synthesis translate_off
    localparam    integer    CHAR_NUM    = 12;
    
    reg [CHAR_NUM*8:1] FB_STATE_1;
    reg [CHAR_NUM*8:1] FB_STATE_2;
    reg [CHAR_NUM*8:1] FB_STATE_3;

    always @(state_1) begin
        case (state_1)
            wait_write:        FB_STATE_1 <= "WAIT_WRITE";
            writing:        FB_STATE_1 <= "WRITING";
            displaying :    FB_STATE_1 <= "DISPLAYING";
            wait_display :    FB_STATE_1 <= "WAIT_DISPLAY";
        endcase
    end

    always @(state_2) begin
        case (state_2)
            wait_write:        FB_STATE_2 <= "WAIT_WRITE";
            writing:        FB_STATE_2 <= "WRITING";
            displaying :    FB_STATE_2 <= "DISPLAYING";
            wait_display :    FB_STATE_2 <= "WAIT_DISPLAY";
        endcase
    end
    
    always @(state_3) begin
        case (state_3)
            wait_write:        FB_STATE_3 <= "WAIT_WRITE";
            writing:        FB_STATE_3 <= "WRITING";
            displaying :    FB_STATE_3 <= "DISPLAYING";
            wait_display :    FB_STATE_3 <= "WAIT_DISPLAY";
        endcase
    end    
    // synthesis translate_on    
endmodule

`default_nettype wire


最後にテストベンチの triple_tb_cntrler_tb.v

// Triple Frame Buffer Controller Testbench
// triple_tb_cntrler_tb.v
//

`default_nettype none

`timescale 1us / 100ps

module triple_tb_cntrler_tb;
    parameter    integer    write_life_cycle    = 100000/15;    // 15fps
    parameter    integer display_life_cycle    = 100000/60;    // 60fps
    
    parameter integer C_M_AXI_ADDR_WIDTH            = 32;
    
    wire    clk;
    wire    reset;
    reg        [23:0] wtime;
    reg        [23:0] dtime;
    wire    [C_M_AXI_ADDR_WIDTH-1 :0]    camera_fb_start_addr;
    wire    [C_M_AXI_ADDR_WIDTH-1 :0]    bitmapd_fb_start_addr;
    wire    frame_valid_1d;
    wire    display_enable;
    
    // clk のインスタンス
    clk_gen #(
        .CLK_PERIOD(10),    // 10usec, 100kHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) clki (
        .clk_out(clk)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b1),
        .RESET_TIME(50)    // 50usec
    ) RESETi (
        .reset_out(reset)
    );

    triple_fb_cntrler #(
        .C_M_AXI_ADDR_WIDTH(C_M_AXI_ADDR_WIDTH),
        .C_DISPLAY_START_ADDRESS(32'h1A000000)
    ) triple_fb_cntrler_i (
        .aclk(clk),
        .aresetn(~reset),
        .camera_fb_start_addr(camera_fb_start_addr),
        .bitmapd_fb_start_addr(bitmapd_fb_start_addr),
        .frame_valid_1d(frame_valid_1d),
        .display_enable(display_enable)
    );
    
    always @(posedge clk) begin
        if (reset)
            wtime <= write_life_cycle - 1;
        else begin
            if (wtime == 24'd0)
                wtime <= write_life_cycle - 1;
            else
                wtime <= wtime - 24'd1;
        end
    end
    assign frame_valid_1d = (wtime > 24'd100) ? 1'b1 : 1'b0;
    
    always @(posedge clk) begin
        if (reset)
            dtime <= display_life_cycle - 1;
        else begin
            if (dtime == 24'd0)
                dtime <= display_life_cycle - 1;
            else
                dtime <= dtime - 24'd1;
        end
    end
    assign display_enable = (dtime > 24'd100) ? 1'b1 : 1'b0;
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
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


  1. 2013年05月10日 05:34 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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