FC2カウンター FPGAの部屋 ビットマップ・ディスプレイ・コントローラの作製19(HDLソースの公開)
FC2ブログ

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

FPGAの部屋

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

ビットマップ・ディスプレイ・コントローラの作製19(HDLソースの公開)

ビットマップ・ディスプレイ・コントローラの作製18(動作した?)”の続き。

一応動作したと思われるので、HDLソースを公開します。無保証ですので、ご了承ください。後でバグがあった場合は修正します。また、バグを見つけた方はコメント欄でお知らせください。長いです。
まずは、画像の表示タイミングを定義する disp_timing_parameters.vh から。
(2012/12/13:修正、(誤)disp_timing_parameter.vh (正)disp_timing_parameters.vh)

//  表示タイミングの定義
    
    // VGA 解像度 pixel clock = 25MHz
    parameter H_ACTIVE_VIDEO= 640;
    parameter H_FRONT_PORCH = 16;
    parameter H_SYNC_PULSE = 96;
    parameter H_BACK_PORCH = 48;
    parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    parameter V_ACTIVE_VIDEO = 480;
    parameter V_FRONT_PORCH = 11;
    parameter V_SYNC_PULSE = 2;
    parameter V_BACK_PORCH = 31;
    parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // SVGA 解像度 pixel clock = 40MHz
    // parameter H_ACTIVE_VIDEO= 800;
    // parameter H_FRONT_PORCH = 40;
    // parameter H_SYNC_PULSE = 128;
    // parameter H_BACK_PORCH = 88;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 600;
    // parameter V_FRONT_PORCH = 1;
    // parameter V_SYNC_PULSE = 4;
    // parameter V_BACK_PORCH = 23;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // XGA 解像度 pixel clock = 65MHz
    // parameter H_ACTIVE_VIDEO= 1024;
    // parameter H_FRONT_PORCH = 24;
    // parameter H_SYNC_PULSE = 136;
    // parameter H_BACK_PORCH = 160;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 768;
    // parameter V_FRONT_PORCH = 2;
    // parameter V_SYNC_PULSE = 6;
    // parameter V_BACK_PORCH = 29;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // SXGA 解像度 pixel clock = 108MHz
    // parameter H_ACTIVE_VIDEO= 1280;
    // parameter H_FRONT_PORCH = 48;
    // parameter H_SYNC_PULSE = 112;
    // parameter H_BACK_PORCH = 248;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 1024;
    // parameter V_FRONT_PORCH = 1;
    // parameter V_SYNC_PULSE = 3;
    // parameter V_BACK_PORCH = 38;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    
    parameter H_DISPLAY_SIZE = H_ACTIVE_VIDEO/8; // 横80桁
    parameter V_DISPLAY_SIZE = V_ACTIVE_VIDEO/8; // 縦60行
    
    parameter RED_DOT_POS = 15; // 15~13ビット目がRED
    parameter GREEN_DOT_POS = 12; // 12~10ビット目がGREEN
    parameter BLUE_DOT_POS = 9; // 9~7ビット目がBLUE
    parameter COLOR_ATTRIB_WIDHT = 3;    // 色情報のビット幅


次に、XPSのpcore のトップの bitmap_disp_cntrler_axi_master.v

// bitmap_disp_cntrler_axi_master.v 
//
// Read Only IP, 64 bit bus
//
// 2012/06/28

`default_nettype none

module bitmap_disp_cntrler_axi_master #
  (
        parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8,
        parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
        parameter integer C_M_AXI_ADDR_WIDTH            = 32,
        parameter integer C_M_AXI_DATA_WIDTH            = 64,
        parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
        parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
        parameter integer C_M_AXI_WUSER_WIDTH           = 1,
        parameter integer C_M_AXI_RUSER_WIDTH           = 1,
        parameter integer C_M_AXI_BUSER_WIDTH           = 1,
        parameter [31:0]  C_M_AXI_TARGET                 = 32'h00000000,
        parameter integer C_M_AXI_BURST_LEN                = 256,
        parameter integer C_OFFSET_WIDTH                = 32,
        
        /* Disabling these parameters will remove any throttling.
        The resulting ERROR flag will not be useful */ 
        parameter integer C_M_AXI_SUPPORTS_WRITE         = 0,
        parameter integer C_M_AXI_SUPPORTS_READ         = 1
    )
    (
        // System Signals
        input wire           ACLK,
        input wire           ARESETN,

        // Master Interface Write Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_AWID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_AWADDR,
        output wire [8-1:0]              M_AXI_AWLEN,
        output wire [3-1:0]              M_AXI_AWSIZE,
        output wire [2-1:0]              M_AXI_AWBURST,
        output wire                  M_AXI_AWLOCK,
        output wire [4-1:0]              M_AXI_AWCACHE,
        output wire [3-1:0]              M_AXI_AWPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
        output wire [4-1:0]              M_AXI_AWQOS,
        output wire [C_M_AXI_AWUSER_WIDTH-1:0]      M_AXI_AWUSER,
        output wire                  M_AXI_AWVALID,
        input  wire                  M_AXI_AWREADY,

        // Master Interface Write Data
        // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
        output wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_WDATA,
        output wire [C_M_AXI_DATA_WIDTH/8-1:0]      M_AXI_WSTRB,
        output wire                  M_AXI_WLAST,
        output wire [C_M_AXI_WUSER_WIDTH-1:0]      M_AXI_WUSER,
        output wire                  M_AXI_WVALID,
        input  wire                  M_AXI_WREADY,

        // Master Interface Write Response
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_BID,
        input  wire [2-1:0]              M_AXI_BRESP,
        input  wire [C_M_AXI_BUSER_WIDTH-1:0]      M_AXI_BUSER,
        input  wire                  M_AXI_BVALID,
        output wire                  M_AXI_BREADY,

        // Master Interface Read Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_ARID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_ARADDR,
        output wire [8-1:0]              M_AXI_ARLEN,
        output wire [3-1:0]              M_AXI_ARSIZE,
        output wire [2-1:0]              M_AXI_ARBURST,
        output wire [2-1:0]              M_AXI_ARLOCK,
        output wire [4-1:0]              M_AXI_ARCACHE,
        output wire [3-1:0]              M_AXI_ARPROT,
        // AXI3 output wire [4-1:0]          M_AXI_ARREGION,
        output wire [4-1:0]              M_AXI_ARQOS,
        output wire [C_M_AXI_ARUSER_WIDTH-1:0]      M_AXI_ARUSER,
        output wire                  M_AXI_ARVALID,
        input  wire                  M_AXI_ARREADY,

        // Master Interface Read Data 
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_RID,
        input  wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_RDATA,
        input  wire [2-1:0]              M_AXI_RRESP,
        input  wire                  M_AXI_RLAST,
        input  wire [C_M_AXI_RUSER_WIDTH-1:0]      M_AXI_RUSER,
        input  wire                  M_AXI_RVALID,
        output wire                  M_AXI_RREADY,
        
        // User Ports
        input    wire    pixclk,
        
        output    wire    TMDS_tx_clk_p,
        output    wire    TMDS_tx_clk_n,
        output    wire    TMDS_tx_2_G_p,
        output    wire    TMDS_tx_2_G_n,
        output    wire    TMDS_tx_1_R_p,
        output    wire    TMDS_tx_1_R_n,
        output    wire    TMDS_tx_0_B_p,
        output    wire    TMDS_tx_0_B_n,
        
        input    wire    ddr_cont_init_done
    );
    
    wire    [7:0]    red, green, blue;
    wire    hsyncx, vsyncx;
    wire    display_enable;
    wire    bde_req, bde_ack;
    wire    [7:0]    bde_arlen;
    wire    [31:0]    bde_address;
    wire    [63:0]    bde_data;
    wire    bde_data_valid;
    reg        reset_disp_2b, reset_disp_1b;
    wire    reset_disp;
    wire    afifo_overflow, afifo_underflow;
    wire    addr_is_zero, h_v_is_zero;
    
    axi_master_interface #(
        .C_M_AXI_THREAD_ID_WIDTH(C_M_AXI_THREAD_ID_WIDTH),
        .C_M_AXI_ADDR_WIDTH(C_M_AXI_ADDR_WIDTH),
        .C_M_AXI_DATA_WIDTH(C_M_AXI_DATA_WIDTH),
        .C_M_AXI_AWUSER_WIDTH(C_M_AXI_AWUSER_WIDTH),
        .C_M_AXI_ARUSER_WIDTH(C_M_AXI_ARUSER_WIDTH),
        .C_M_AXI_WUSER_WIDTH(C_M_AXI_WUSER_WIDTH),
        .C_M_AXI_RUSER_WIDTH(C_M_AXI_RUSER_WIDTH),
        .C_M_AXI_BUSER_WIDTH(C_M_AXI_BUSER_WIDTH),
        .C_M_AXI_SUPPORTS_WRITE(C_M_AXI_SUPPORTS_WRITE),
        .C_M_AXI_SUPPORTS_READ(C_M_AXI_SUPPORTS_READ)
    ) axi_master_inf_inst
    (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .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), 
        
        .bde_req(bde_req),
        .bde_ack(bde_ack),
        .bde_arlen(bde_arlen),
        .bde_address(bde_address),
        .bde_data_out(bde_data),
        .bde_data_valid(bde_data_valid)
    );
    
    bitmap_disp_engine bitmap_disp_eng_inst (
        .clk_disp(pixclk),
        .clk_axi(ACLK),
        .reset_disp(reset_disp),
        .reset_axi(~ARESETN),
        .req(bde_req),
        .ack(bde_ack),
        .ARLEN(bde_arlen),
        .address(bde_address),
        .data_in(bde_data),
        .data_valid(bde_data_valid),
        .red_out(red),
        .green_out(green),
        .blue_out(blue),
        .hsyncx(hsyncx),
        .vsyncx(vsyncx),
        .display_enable(display_enable),
        .ddr_cont_init_done(ddr_cont_init_done),
        .afifo_overflow(afifo_overflow),
        .afifo_underflow(afifo_underflow),
        .addr_is_zero(addr_is_zero),
        .h_v_is_zero(h_v_is_zero)
    );
    
    dvi_disp #(
        .PLL_CLKFBOUT_MULT(20),        // クロック倍率 PLL VCO Freq 400MHz ~ 1000MHz
        .PLL_CLKIN_PERIOD(40.0),    // 40 ns, VGA, 640x480
        .PLL_CLKOUT0_DIVIDE(2),        // ピクセルクロックX10
        .PLL_CLKOUT1_DIVIDE(20),    // ピクセルクロック
        .PLL_CLKOUT2_DIVIDE(10)        // ピクセルクロックX2
    ) dvi_disp_inst
    (
        .pixclk(pixclk),
        .reset_in(reset_disp),
        .red_in(red),
        .green_in(green),
        .blue_in(blue),
        .hsync(hsyncx),
        .vsync(vsyncx),
        .display_enable(display_enable),
        .TMDS_tx_clk_p(TMDS_tx_clk_p), 
        .TMDS_tx_clk_n(TMDS_tx_clk_n), 
        .TMDS_tx_2_G_p(TMDS_tx_2_G_p), 
        .TMDS_tx_2_G_n(TMDS_tx_2_G_n), 
        .TMDS_tx_1_R_p(TMDS_tx_1_R_p), 
        .TMDS_tx_1_R_n(TMDS_tx_1_R_n), 
        .TMDS_tx_0_B_p(TMDS_tx_0_B_p), 
        .TMDS_tx_0_B_n(TMDS_tx_0_B_n)
    );
    
    always @(posedge pixclk) begin
        reset_disp_2b <= ~ARESETN;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;
endmodule

`default_nettype wire


次に、AXI4バスとのインターフェースの axi_master_interface.v です。ビットマップ・ディスプレイ・コントローラはDDR2 SDRAMからReadするだけなので、Write側は実装していません。

// axi_master_interface.v
//
// Read Only IP, 64 bit bus
//
// 2012/06/28

`default_nettype none

module axi_master_interface #
  (
        parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
        parameter integer C_M_AXI_ADDR_WIDTH            = 32,
        parameter integer C_M_AXI_DATA_WIDTH            = 64,
        parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
        parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
        parameter integer C_M_AXI_WUSER_WIDTH           = 1,
        parameter integer C_M_AXI_RUSER_WIDTH           = 1,
        parameter integer C_M_AXI_BUSER_WIDTH           = 1,

        /* Disabling these parameters will remove any throttling.
        The resulting ERROR flag will not be useful */ 
        parameter integer C_M_AXI_SUPPORTS_WRITE         = 0,
        parameter integer C_M_AXI_SUPPORTS_READ         = 1
    )
    (
        // System Signals
        input wire           ACLK,
        input wire           ARESETN,

        // Master Interface Write Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_AWID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_AWADDR,
        output wire [8-1:0]              M_AXI_AWLEN,
        output wire [3-1:0]              M_AXI_AWSIZE,
        output wire [2-1:0]              M_AXI_AWBURST,
        output wire                  M_AXI_AWLOCK,
        output wire [4-1:0]              M_AXI_AWCACHE,
        output wire [3-1:0]              M_AXI_AWPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
        output wire [4-1:0]              M_AXI_AWQOS,
        output wire [C_M_AXI_AWUSER_WIDTH-1:0]      M_AXI_AWUSER,
        output wire                  M_AXI_AWVALID,
        input  wire                  M_AXI_AWREADY,

        // Master Interface Write Data
        // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
        output wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_WDATA,
        output wire [C_M_AXI_DATA_WIDTH/8-1:0]      M_AXI_WSTRB,
        output wire                  M_AXI_WLAST,
        output wire [C_M_AXI_WUSER_WIDTH-1:0]      M_AXI_WUSER,
        output wire                  M_AXI_WVALID,
        input  wire                  M_AXI_WREADY,

        // Master Interface Write Response
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_BID,
        input  wire [2-1:0]              M_AXI_BRESP,
        input  wire [C_M_AXI_BUSER_WIDTH-1:0]      M_AXI_BUSER,
        input  wire                  M_AXI_BVALID,
        output wire                  M_AXI_BREADY,

        // Master Interface Read Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_ARID,
        output reg  [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_ARADDR,
        output reg  [8-1:0]              M_AXI_ARLEN,
        output wire [3-1:0]              M_AXI_ARSIZE,
        output wire [2-1:0]              M_AXI_ARBURST,
        output wire [2-1:0]              M_AXI_ARLOCK,
        output wire [4-1:0]              M_AXI_ARCACHE,
        output wire [3-1:0]              M_AXI_ARPROT,
        // AXI3 output wire [4-1:0]          M_AXI_ARREGION,
        output wire [4-1:0]              M_AXI_ARQOS,
        output wire [C_M_AXI_ARUSER_WIDTH-1:0]      M_AXI_ARUSER,
        output wire                  M_AXI_ARVALID,
        input  wire                  M_AXI_ARREADY,

        // Master Interface Read Data 
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_RID,
        input  wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_RDATA,
        input  wire [2-1:0]              M_AXI_RRESP,
        input  wire                  M_AXI_RLAST,
        input  wire [C_M_AXI_RUSER_WIDTH-1:0]      M_AXI_RUSER,
        input  wire                  M_AXI_RVALID,
        output wire                  M_AXI_RREADY,
        
        // bitmap_disp_engine Interface
        input    wire    bde_req,
        output    reg    bde_ack,
        input    wire    [7:0]    bde_arlen,
        input    wire    [31:0]    bde_address,
        output    reg        [63:0]    bde_data_out,
        output    reg        bde_data_valid
    );
    
    parameter    RESP_OKAY =        2'b00,
                RESP_EXOKAY =    2'b01,
                RESP_SLVERR =    2'b10,
                RESP_DECERR =    2'b11;
    
    reg        reset_1d, reset;
    
    parameter    idle_rd =            4'b0001,
                arvalid_assert =    4'b0010,
                data_read =            4'b0100,
                rd_tran_end =        4'b1000;
    reg        [3:0]    rdt_cs;
    
    reg        arvalid;
    reg        [63:0]    read_data;
    reg        rready;
    
    // ARESETN をACLK で同期化
    always @(posedge ACLK) begin
        reset_1d <= ~ARESETN;
        reset <= reset_1d;
    end
    
    // Write は無し
    assign    M_AXI_AWID = 0;
    assign    M_AXI_AWADDR = 0;
    assign    M_AXI_AWLEN = 0;
    assign    M_AXI_AWSIZE = 0;
    assign    M_AXI_AWBURST = 0;
    assign    M_AXI_AWLOCK = 0;
    assign    M_AXI_AWCACHE = 0;
    assign    M_AXI_AWPROT = 0;
    assign    M_AXI_AWQOS = 0;
    assign    M_AXI_AWUSER = 0;
    assign    M_AXI_AWVALID = 0;
    assign    M_AXI_WDATA = 0;
    assign    M_AXI_WSTRB = 0;
    assign    M_AXI_WLAST = 0;
    assign    M_AXI_WUSER = 0;
    assign    M_AXI_WVALID = 0;
    assign    M_AXI_BREADY = 0;

    // Read
    
    // AXI4バス Read Transaction State Machine
    always @(posedge ACLK) begin
        if (reset) begin
            rdt_cs <= idle_rd;
            arvalid <= 1'b0;
            rready <= 1'b0;
        end else begin
            case (rdt_cs)
                idle_rd :
                    if (bde_req) begin
                        rdt_cs <= arvalid_assert;
                        arvalid <= 1'b1;
                    end
                arvalid_assert :
                    if (M_AXI_ARREADY) begin
                        rdt_cs <= data_read;
                        arvalid <= 1'b0;
                        rready <= 1'b1;
                    end
                data_read :
                    if (M_AXI_RLAST && M_AXI_RVALID) begin // 終了
                        rdt_cs <= rd_tran_end;
                        rready <= 1'b0;
                    end
                rd_tran_end :
                    rdt_cs <= idle_rd;
            endcase
        end
    end
    assign M_AXI_ARVALID = arvalid;
    assign M_AXI_RREADY = rready;
    
    assign M_AXI_ARID = 0;
    
    // M_AXI_ARADDR の処理
    always @(posedge ACLK) begin
        if (reset)
            M_AXI_ARADDR <= 0;
        else begin
            if (bde_req)
                M_AXI_ARADDR <= bde_address;
        end
    end
    
    // M_AXI_ARLEN の処理
    always @(posedge ACLK) begin
        M_AXI_ARLEN <= bde_arlen;
    end
    
    assign M_AXI_ARSIZE = 3'b011;        // 8 Bytes in Transfer
    assign M_AXI_ARBURST = 2'b01;        // INCR
    assign M_AXI_ARLOCK = 2'b00;        // Normal Access
    assign M_AXI_ARCACHE = 4'b0010;    // Normal Non-cacheable Non-bufferable
    assign M_AXI_ARPROT = 3'b000;        // Data access, Secure access, Unprivileged access
    assign M_AXI_ARQOS = 4'b0000;        // default
    assign M_AXI_ARUSER = 1'b0;
    
    // bde_ack の処理
    always @(posedge ACLK) begin
        if (arvalid && M_AXI_ARREADY)
            bde_ack <= 1'b1;
        else
            bde_ack <= 1'b0;
    end
    
    // bde_data_out の処理
    always @(posedge ACLK) begin
        bde_data_out <= M_AXI_RDATA;
    end
    
    // bde_data_valid の処理
    always @(posedge ACLK) begin
        if (rready && M_AXI_RVALID)
            bde_data_valid <= 1'b1;
        else
            bde_data_valid <= 1'b0;
    end
    
endmodule


ビットマップ・ディスプレイ・コントローラの中核部で、水平同期、垂直同期を作ったり、DDR2 SDRAMからピクセルデータを読んでくるように指示する bitmap_disp_engine.v です。

// BitMap Display Controller
// bitmap_disp_engine.v
// AXI4バス用

`default_nettype none

// synthesis translate_off
// `include "std_ovl_defines.h"
// synthesis translate_on

module bitmap_disp_engine (    
    input    wire    clk_disp,            // ディスプレイ表示用クロック
    input    wire    clk_axi,            // AXI4バスクロック
    input    wire    reset_disp,            // clk_disp 用リセット
    input    wire    reset_axi,            // clk_axi 用リセット
    output    reg        req,                // Read Address転送のrequest
    input    wire    ack,                // Read Address転送のacknowlege 
    output    reg        [7:0]    ARLEN,        // Read Address転送のバースト長-1
    output    wire    [31:0]    address,    // AXI4 Busのアドレス
    input    wire    [63:0]    data_in,    // DDR2 SDRAMの画像データ(2つのRGB)
    input    wire    data_valid,
    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    output    reg     hsyncx,
    output    reg     vsyncx,
    output    reg        display_enable,
    input    wire    ddr_cont_init_done,    // DDR2 SDRAMコントローラの初期化終了
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow,    // 非同期FIFO のアンダーフロー・エラー
    output    reg        addr_is_zero,    // for test
    output    reg        h_v_is_zero        // for test
);
    `include "./disp_timing_parameters.vh"
    
    parameter DDR2_SDRAM_START_ADDRESS = 32'h2000_0000;    // DDR2 SDRAMのスタートアドレス
    
    parameter AFIFO_FULL_VAL = 8'b1000_0000; // Write側の値。Write側は32ビットなので、128でRead側は256となる
    parameter AFIFO_HALF_FULL_VAL = 8'b0100_0000; // Write側の値。Write側は32ビットなので、64でRead側は128となる
    
    parameter [5:0]    idle_rdg=            6'b000001,
                    init_full_mode=        6'b000010,
                    wait_half_full=        6'b000100,
                    req_burst=            6'b001000,
                    frame_wait_state=    6'b010000,
                    frame_start_full=    6'b100000;
    reg    [5:0] cs_rdg;
    
    parameter [2:0]    IDLE_REQ =        3'b001,
                    REQ_ASSERT =    3'b010,
                    REQ_HOLD =        3'b100;
    reg [2:0]    cs_req;
    
    reg afifo_rd_en;
    wire [31:0] afifo_dout;
    wire afifo_full;
    wire afifo_empty;
    wire [7:0] wr_data_count;
    reg [31:0] addr_count;
    (* KEEP="TURE" *) wire hv_count_enable;
    reg [7:0] read_count;
    (* KEEP="TURE" *) reg hv_cnt_ena_d1;
    (* KEEP="TURE" *) reg hv_cnt_ena_d2;
    reg [11:0] h_count;
    reg [11:0] v_count;
    reg [7:0] red_node, green_node, blue_node;
    reg hsyncx_node, vsyncx_node;
    reg addr_is_zero_node, h_v_is_zero_node;
    reg vsync_axi, vsync_axi_b1;
    reg vsync_axi_1d;
    reg vsyncx_rise_pulse;

    // synthesis translate_off
    // wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow;
    // synthesis translate_on
    
    // RGB保存用非同期FIFO, FWFT Wirte側64ビット幅128深度、Read側32ビット256深度とする
    bitmap_afifo bitmap_afifo_inst (
        .wr_rst(reset_axi | vsync_axi),
        .wr_clk(clk_axi),
        .rd_clk(clk_disp),
        .rd_rst(reset_disp | ~vsyncx_node),
        .din(data_in), // Bus [63 : 0] 
        .wr_en(data_valid),
        .rd_en(afifo_rd_en),
        .dout(afifo_dout), // Bus [31 : 0] 
        .full(afifo_full),
        .overflow(afifo_overflow),
        .empty(afifo_empty),
        .underflow(afifo_underflow),
        .wr_data_count(wr_data_count) // Bus [7 : 0] 
    );
    
    // AXI4 Busのアドレスカウンタ(AXI4クロックドメイン)カウンタの単位は1バイト
    always @(posedge clk_axi) begin
        if (reset_axi)
            addr_count <= DDR2_SDRAM_START_ADDRESS;
        else begin
            // if (addr_count>=(DDR2_SDRAM_START_ADDRESS + (H_ACTIVE_VIDEO * V_ACTIVE_VIDEO *4))) // 1フレーム分描画終了したのでクリアする(1ピクセルに3バイト使用する。つまり32ビット(4bytes)使用するので*4する)
            if (vsync_axi)
                addr_count <= DDR2_SDRAM_START_ADDRESS;
            else if (data_valid) // データが来たらカウントアップ
                addr_count <= addr_count + 32'd8; // 1回のデータは64ビット長(8バイト)
        end
    end
    assign address = addr_count;
    
    // 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;
    
    // req の実装。VRAMのデータをReadしたいときにアクティベート。ackが帰ってきたら落とす
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            cs_req <= IDLE_REQ;
            req <= 1'b0;
        end else begin
            case (cs_req)
                IDLE_REQ : 
                    if (cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full) begin
                        cs_req <= REQ_ASSERT;
                        req <= 1'b1;
                    end
                REQ_ASSERT :
                    if (ack) begin
                        cs_req <= REQ_HOLD;
                        req <= 1'b0;
                    end
                REQ_HOLD :
                    if (~(cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full))
                        cs_req <= IDLE_REQ;
            endcase
        end
    end
    
    // ARLEN, read_count の決定。 init_full_mode,frame_start_full  の時はAFIFO_FULL_VAL-1、それ以外はAFIFO_HALF_FULL_VAL-1
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            ARLEN <= AFIFO_FULL_VAL-1;
            read_count <= AFIFO_FULL_VAL;
        end else begin
            if (cs_rdg==idle_rdg || cs_rdg==frame_wait_state) begin
                ARLEN <= AFIFO_FULL_VAL-1;
                read_count <= AFIFO_FULL_VAL;
            end else if (cs_rdg==wait_half_full) begin
                ARLEN <= AFIFO_HALF_FULL_VAL-1;
                read_count <= AFIFO_HALF_FULL_VAL;
            end else if (cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full) begin
                if (read_count!=0 && data_valid) // 0になるまで、データが来たらデクリメント
                    read_count <= read_count - 1;
            end
        end
    end
    
    // read_count の実装、AXI4 Bus Interface へのRead要求のカウントをする。
    // always @(posedge clk_axi) begin
        // if (reset_axi)
            // read_count <= ARLEN+1;
        // else begin
            // if (cs_rdg==wait_half_full || cs_rdg==idle_rdg)
                // read_count <= ARLEN+1;
            // else if (cs_rdg==req_burst || cs_rdg==init_full_mode) begin
                // if (read_count!=0 && data_valid) // 0になるまで、データが来たらデクリメント
                    // read_count <= read_count - 1;
            // end
        // end
    // end
    
    // ビットマップVGAコントローラのclk_disp 動作部
    
    // 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 + 11'd1;
    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 + 10'd1;
        end
    end
    
    // Red, Green, Blue出力
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_node <= 0;
            green_node <= 0;
            blue_node <= 0;
        end else begin
            if (~hv_cnt_ena_d2) begin // 最初にpixel_async_fifo がフルになるまで画像データを出力しない。
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) begin
                red_node <= afifo_dout[23:16];
                green_node <= afifo_dout[15:8];
                blue_node <= afifo_dout[7:0];
            end else begin
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end 
                
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_out <= 0;
            green_out <= 0;
            blue_out <= 0;
        end else begin
            red_out <= red_node;
            green_out <= green_node;
            blue_out <= blue_node;
        end
    end
    
    // hsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx_node <= 1'b1;
        else
            if (h_count>(H_ACTIVE_VIDEO + H_FRONT_PORCH-1) && h_count<=(H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE-1)) // 水平同期期間
                hsyncx_node <= 1'b0;
            else
                hsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx <= 1'b1;
        else
            hsyncx <= hsyncx_node;
    end
    
    // vsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx_node <= 1'b1;
        else
            if (v_count>(V_ACTIVE_VIDEO + V_FRONT_PORCH-1) && v_count<=(V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE-1)) // 垂直同期期間
                vsyncx_node <= 1'b0;
            else
                vsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx <= 1'b1;
        else
            vsyncx <= vsyncx_node;
    end

    // vsync をclk_axi で同期化
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            vsync_axi        <= 1'b0;
            vsync_axi_b1    <= 1'b0;
            vsync_axi_1d    <= 1'b0;
        end else begin
            vsync_axi_b1     <= ~vsyncx_node;
            vsync_axi         <= vsync_axi_b1;
            vsync_axi_1d    <= vsync_axi;
        end
    end
    
    // vsyncx_rise_pulse の処理。vsyncx の立ち上がり時に1パルス出力する
    always @(posedge clk_axi) begin
        if (reset_axi)
            vsyncx_rise_pulse <= 1'b0;
        else begin
            if (vsync_axi==1'b0 && vsync_axi_1d==1'b1)
                vsyncx_rise_pulse <= 1'b1;
            else
                vsyncx_rise_pulse <= 1'b0;
        end
    end
    
    // display_enable 出力
    always @(posedge clk_disp) begin
        if (reset_disp)
            display_enable <= 1'b1;
        else begin
            if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO)
                display_enable <= 1'b1;
            else
                display_enable <= 1'b0;
        end
    end
    
    // afifo_rd_en の処理
    always @(posedge clk_disp) begin
        if (reset_disp)
            afifo_rd_en <= 1'b0;
        else begin
            if (~hv_cnt_ena_d2) // 初期化中
                afifo_rd_en <= 1'b0;
            else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) // 表示期間
                afifo_rd_en <= 1'b1;
            else
                afifo_rd_en <= 1'b0;
        end
    end

    
    // アサーション
    // synthesis translate_off
    always @ (posedge clk_axi) begin
        if (reset_axi)
            ;
        else begin
            if (afifo_overflow) begin 
                $display("%m: at time %t ERROR : FIFOがフルなのにライトした",$time);
                $stop;
            end
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            ;
        else begin
            if (afifo_underflow) begin
                $display("%m: at time %t ERROR : FIFOが空なのにリードした",$time);
                $stop;
            end
        end
    end
    
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOがフルなのにライトした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_overflow_assertion (
        // clk_axi,
        // reset_axi,
        // 1'b1,
        // afifo_overflow,
        // fire_overflow
    // );
        
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOが空なのにリードした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_underflow_assertion (
        // clk_disp,
        // reset_disp,
        // 1'b1,
        // afifo_underflow,
        // fire_underflow
    // );
    // synthesis translate_on
    
    //  for test
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            addr_is_zero_node <= 1'b0;
            addr_is_zero <= 1'b0;
        end else begin
            if (addr_count == 0)
                addr_is_zero_node <= 1'b1;
            else
                addr_is_zero_node <= 1'b0;
            addr_is_zero <= addr_is_zero_node;
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= 1'b0;
        end else begin
            if (h_count==0 && v_count==0)
                h_v_is_zero_node <= 1'b1;
            else
                h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= h_v_is_zero_node;
        end
    end
            
endmodule

`default_nettype wire


次に、bitmap_afifo.v だが、これは、IPとしてCoreGenで生成したので、ここには載せないことにします。代わりに、Fifo Generator の設定画面を載せておきます。
BitMapDispCont_122_120822.png

BitMapDispCont_123_120822.png

BitMapDispCont_124_120822.png

BitMapDispCont_125_120822.png

BitMapDispCont_126_120822.png

BitMapDispCont_127_120822.png

BitMapDispCont_128_120822.png

dvi_disp.vhd については、”DVI、HDMIの勉強6(キャラクタ・ディスプレイ・コントローラをDVI出力にする VHDL編1)”にVHDLソースコードを貼ってあります。

XPSにpcoreフォルダ関連のファイルやそのやり方については、以下のブログ記事を参考にしてください。
ビットマップ・ディスプレイ・コントローラの作製9(BitMapDCの接続1)
ビットマップ・ディスプレイ・コントローラの作製10(BitMapDCの接続2)
ビットマップ・ディスプレイ・コントローラの作製11(BitMapDCの接続3)
ビットマップ・ディスプレイ・コントローラの作製12(BitMapDCのインプリメント1)

最後にXPSの構成画面を下に貼っておきます。
BitMapDispCont_129_120822.png
  1. 2012年08月22日 04:51 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/2230-efd53039
この記事にトラックバックする(FC2ブログユーザー)