FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

XilinxのAXI BRAM Controllerの使い方がやっと分かった

まあちゃんとマニュアル読めということなんだろうけど。

XilinxのIPには、AXI BRAM Controllerという、BlockRAMモジュールを繋げるためのIPが存在する。

http://www.xilinx.com/support/documentation/ip_documentation/axi_bram_ctrl/v4_0/pg078-axi-bram-ctrl.pdf

これ、コントローラなので、BRAM本体は別売が正しい。最初はコントローラとBRAMが接続されているのかと思った。 インタフェースはAXI、BRAMとの接続はNativeなBRAM I/Fを用いる。

f:id:msyksphinz:20150411023055j:plain

  • s_axi_* : AXIのインタフェース
  • bram*{a,b} : Block RAMのインタフェース

このインタフェースを接続するために、仮想のBlockRAMモデルを作った。この方が初期化とかがやりやすい。

module bram_model
    #(parameter width  = 32,   //% Data width (default is 32bit)
      parameter id_w   = 4,    //% Request ID width (default is 4)
      parameter words  = 128,  //% RAM size (default is 128words)
      parameter length = 7)    //% Address size (ideally 2^length == words)
    (
     input wire                bram_clk_a, //% Port-0 clock
     input wire                bram_clk_b, //% Port-1 clock

     input wire                bram_rst_a, //% Port-0 clock
     input wire                bram_rst_b, //% Port-1 clock

     input wire                bram_en_a, //% Port-0 Request Valid
     input wire                bram_en_b, //% Port-1 Request Valid

     input wire [width/8-1: 0] bram_we_a, //% Port-0 Write Request Valid
     input wire [width/8-1: 0] bram_we_b, //% Port-1 Write Request Valid

     input wire [width-1: 0]   bram_wrdata_a, //% Port-0 Write Data Valid
     input wire [width-1: 0]   bram_wrdata_b, //% Port-1 Write Data Valid

     input wire [length-1: 0]  bram_addr_a, //% Port-0 Address
     input wire [length-1: 0]  bram_addr_b, //% Port-1 Address

     output reg [width-1: 0]   bram_rddata_a, //% Port-0 Read Data
     output reg [width-1: 0]   bram_rddata_b  //% Port-1 Read Data
     );

    reg [width-1: 0]          regs[words-1: 0]; //% Register instance.
    localparam addr_offset = width/8/4;
    /*!
     * Port-0 Read/Write operation.
     * bram_en_a & bram_we_a is needed to write RAM.
     * bram_en_a is needed to read RAM.
     */
    wire [length-1:addr_offset] bram_addr_a_in;
    wire [width-1: 0]           bram_wrdata_a_in, bram_wrdata_a_tmp;
    assign bram_addr_a_in    = bram_addr_a[length-1:addr_offset];
    assign bram_wrdata_a_tmp = regs[bram_addr_a_in];
    genvar                    a_i;
    generate for (a_i = 0; a_i < width/8; a_i = a_i + 1) begin
        assign bram_wrdata_a_in[8*a_i+7:8*a_i] = bram_we_a[a_i] ? bram_wrdata_a[8*a_i+7:8*a_i] :
                                                 bram_wrdata_a_tmp[8*a_i+7:8*a_i];
    end
    endgenerate
    always @ (posedge bram_clk_a) begin
        bram_rddata_a <= regs[bram_addr_a_in];
        if ((bram_en_a & |bram_we_a) == `Enable) begin
            regs[bram_addr_a_in] <= bram_wrdata_a_in;
        end
    end // always @ (posedge bram_clk_a)

    /*!
     * Port-1 Read/Write operation.
     * bram_en_b & bram_we_b is needed to write RAM.
     * bram_en_b is needed to read RAM.
     */
    wire [length-1:addr_offset] bram_addr_b_in;
    wire [width-1: 0]           bram_wrdata_b_in, bram_wrdata_b_tmp;
    assign bram_addr_b_in    = bram_addr_b[length-1:addr_offset];
    assign bram_wrdata_b_tmp = regs[bram_addr_b_in];
    genvar                    b_i;
    generate for (b_i = 0; b_i < width/8; b_i = b_i + 1) begin
        assign bram_wrdata_b_in[8*b_i+7:8*b_i] = bram_we_b[b_i] ? bram_wrdata_b[8*b_i+7:8*b_i] :
                                                 bram_wrdata_b_tmp[8*b_i+7:8*b_i];
    end
    endgenerate
    always @ (posedge bram_clk_b) begin
        bram_rddata_b <= regs[bram_addr_b_in];
        if ((bram_en_b & bram_we_b) == `Enable) begin
            regs[bram_addr_b_in] <= bram_wrdata_b_in;
        end
    end // always @ (posedge bram_clk_b)

    integer init_i;
    initial begin
        for (init_i = 0; init_i < words; init_i = init_i + 1) begin
            regs[init_i] = {width{1'b0}};
        end
    end

endmodule // axiram

これは論理合成できない、というか出来ても凄く効率が悪いので、論理合成するときは本物のBlockRAMのIPに置き換える。

http://www.xilinx.com/support/documentation/ip_documentation/blk_mem_gen_ds512.pdf