FC2カウンター FPGAの部屋 Vivado 2014.4でのVerilog HDLで記述したROM の初期化データの扱い
FC2ブログ

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

FPGAの部屋

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

Vivado 2014.4でのVerilog HDLで記述したROM の初期化データの扱い

Vivado HLS 2014.1で生成したラプラシアンフィルタIPをシミュレーション5(シミュレーション用プロジェクトの作製)”でシミュレーション用のプロジェクトが完成したので、シミュレーションを行った。
しかし、”Vivado HLS 2014.1で生成したラプラシアンフィルタIPをシミュレーション2(reg_set_axi_lite_master IP の作製)”で、Vivado のIPとしたreg_set_axi_lite_master.v のrom 配列にラプラシアンフィルタIP を初期化して、ラプラシアンフィルタ処理をスタートする処理を書き込むことが出来ない。これは、”AXI VDMAのレジスタ設定用AXI Lite Master IPの作製2(シミュレーション)”に詳しく書かれているが、rom という2次元配列に initial 文で $readmemh("vdma_reg_set.txt", rom, 0, 255); を使用して、vdma_reg_set.txt に書いたアドレスとデータを読み込むようになっている。
今回は、vdma_reg_set.txt では、名前が良くないので、reg_set.txt に変更してある。

reg_set.txt をシミュレーションの時の work フォルダに置けば読まれるはずなのだが、プロジェクト内の何処においても読まれない。とっても困ってしまった。

現象としては、Vivado の Flow Navigator -> Simulation -> Run Simulation をクリックして、Run Behavioral Simulation を実行すると、エラボレーション時に、WARNINGが出て、reg_set_axi_lite_master_0 の rom[0:255][31:0] の内容が XXXXXXXX になってしまう。
lap_fil_hls_14_1_9_150312.png

WARNINGの内容を下に示す。

WARNING: File reg_set.txt referenced on Z:/Sim/lap_fil_hls_14_1/lap_fil_hls_14_1.srcs/sources_1/ipshared/marsee/reg_set_axi_lite_master_v1_0/087f6a47/reg_set_axi_lite_master.v at line 59 cannot be opened for reading. Please ensure that this file is available in the current working directory.



ファイル名が Verilog HDL ファイル内で固定されていると、ファイル名やパスを変えるのにIPを変更する必要が出てくるので、もう一度、reg_set_axi_lite_master IP を初期化ファイル名を parameter で変更できるように書き換えようと思う。

reg_set_axi_lite_master.v にROM_INITIALIZATION_FILE parameter を追加した。

module reg_set_axi_lite_master # (
    parameter integer C_M_AXI_ADDR_WIDTH = 32,
    parameter integer C_M_AXI_DATA_WIDTH = 32,
    parameter ROM_INITIALIZATION_FILE = "reg_set.dat"
)(


次に再度 IP化を行った。

Customization Parameters
lap_fil_hls_14_1_6_150312.png

Customization GUI
lap_fil_hls_14_1_7_150312.png

Review and Package を選択して、Re-Package IP ボタンをクリックして、再度 IP 化を行った。
lap_fil_hls_14_1_8_150312.png

reg_set_axi_lite_master IP が変更できた。
ブロック・デザイン上のROM初期化データファイル名を reg_set.txt として、reg_set_axi_lite_master IP の ROM_INITIALIZATION_FILE にフルパス(Z:/Sim/lap_fil_hls_14_1/Simulation/reg_set.txt)で入力した。
lap_fil_hls_14_1_11_150312.png

これで、もう一度、シミュレーションをしてみると、reg_set_axi_lite_master IP の rom に初期化データが入力された。
lap_fil_hls_14_1_12_150312.png

次に、macchan_jp さんに教えてもらった方法を試してみる。それは、初期化データファイルをVivado のプロジェクトに入れてしまうことだ。教えてもらったのは、.dat ファイルをプロジェクトに入れる方法なのだが、私は、ダブルクリックした時に表示してくれるので、.txt ファイルを使用した。シミュレーションの場合には .txt ファイルでも .dat ファイルでもどちらでも初期化データファイルとして使えるようだが、インプリメントの際には .dat ファイルでないとインプリメント出来ないようだ。どちらかと言ったら .dat ファイルを初期化データファイルとして使うことをお勧めする。

初期化データファイルをプロジェクトに入れる方法だと、プロジェクトを配布してファイルへのパスが変わっても問題ないので、絶対パスを入れるよりも良いと思う。それではやってみよう。

まずは、reg_set_axi_lite_master IPの ROM_INITIALIZATION_FILE parameter を reg_set.txt に戻した。
lap_fil_hls_14_1_10_150312.png

File メニューから Add Source... を選択する。

Add Source ダイアログで Add or create simulation sources ラジオボタンを選択する。
lap_fil_hls_14_1_13_150312.png

Add Files... ボタンをクリックして、reg_set.txt を選択する。
lap_fil_hls_14_1_14_150312.png

Simulation Sources に reg_set.txt が入った。
lap_fil_hls_14_1_15_150312.png

これでシミュレーションをすると、絶対パス指定の時と同様に、reg_set_axi_lite_master IP の rom に初期化データが入力された。
lap_fil_hls_14_1_12_150312.png

最後に、reg_set_axi_lite_master.v を貼っておく。

///////////////////////////////////////////////////////////////////////////////
//
// AXI4/Lite Master
//
////////////////////////////////////////////////////////////////////////////
//
// Structure:
//   reg_set_axi_lite_master
//
////////////////////////////////////////////////////////////////////////////

`default_nettype none

module reg_set_axi_lite_master # (
    parameter integer C_M_AXI_ADDR_WIDTH = 32,
    parameter integer C_M_AXI_DATA_WIDTH = 32,
    parameter ROM_INITIALIZATION_FILE = "reg_set.dat"
)(
    // System Signals
    input wire M_AXI_ACLK,
    input wire M_AXI_ARESETN,

    // Master Interface Write Address
    output wire [C_M_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR,
    output wire [3-1:0] M_AXI_AWPROT,
    output wire M_AXI_AWVALID,
    input wire M_AXI_AWREADY,

    // Master Interface Write Data
    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_WVALID,
    input wire M_AXI_WREADY,

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

    // Master Interface Read Address
    output wire [C_M_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR,
    output wire [3-1:0] M_AXI_ARPROT,
    output wire M_AXI_ARVALID,
    input wire M_AXI_ARREADY,

    // Master Interface Read Data 
    input wire [C_M_AXI_DATA_WIDTH-1:0] M_AXI_RDATA,
    input wire [2-1:0] M_AXI_RRESP,
    input wire M_AXI_RVALID,
    output wire M_AXI_RREADY,
    
    input    wire    init_done
);

    reg        [31:0] rom [0:255];
    reg        [31:0] rom_dout;
    
    initial begin
        $readmemh(ROM_INITIALIZATION_FILE, rom, 0, 255);
    end
    
    reg        reset_1b, reset;
    reg     [31:0]    reg_addr;
    reg        [31:0]    reg_data;
    reg     [7:0]    rom_addr;
    reg        awvalid;
    reg        wvalid;
    reg        bready;

    localparam    RESP_OKAY =        2'b00,
                RESP_EXOKAY =    2'b01,
                RESP_SLVERR =    2'b10,
                RESP_DECERR =    2'b11;
    
    localparam    IDLE_RRSM =                3'b000,
                ADDRESS_READ =            3'b001,
                DATA_READ =                3'b011,
                REG_SET_DATA_VALID =    3'b010,
                END_RRSM =                3'b110;
    reg        [2:0]    rrsm_cs;
    
    localparam    IDLE_ADDR =            2'b00,
                AWVALID_ASSERT =    2'b01,
                AWVALID_HOLD_OFF =    2'b11;
    reg        [1:0]    addr_cs;
    
    localparam    IDLE_DATA =            2'b00,
                WVALID_ASSERT =        2'b01,
                WVALID_HOLD_OFF =    2'b11;
    reg        [1:0]    data_cs;
    
    localparam    IDLE_RESP =        1'b0,
                BREADY_ASSERT =    1'b1;
    reg        resp_cs;
    
    reg        reg_data_valid;
    reg        rom_read_done;
    
    // Read is not implement
    assign M_AXI_ARADDR = 0;
    assign M_AXI_ARPROT = 3'd0;
    assign M_AXI_ARVALID = 1'b0;
    assign M_AXI_RDATA = 0;
    assign M_AXI_RREADY = 1'b1;
    assign M_AXI_WSTRB = 4'b1111;
    assign M_AXI_AWPROT = 3'b000;
    
    // reset
    always @(posedge M_AXI_ACLK) begin
        reset_1b <= ~M_AXI_ARESETN | ~init_done;
        reset <= reset_1b;
    end
    
    // instantiaton of rom
    always @(posedge M_AXI_ACLK) begin
        rom_dout <= rom[rom_addr];
    end
    
    // rom read State Machine
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            rrsm_cs <= IDLE_RRSM;
            reg_data_valid <= 1'b0;
        end else begin
            case (rrsm_cs) 
                IDLE_RRSM : 
                    rrsm_cs <= ADDRESS_READ;
                ADDRESS_READ :
                    rrsm_cs <= DATA_READ;
                DATA_READ : begin
                    if (rom_dout == 32'hFFFF_FFFF) begin // end
                        rrsm_cs <= END_RRSM;
                        reg_data_valid <= 1'b0;
                    end else begin
                        rrsm_cs <= REG_SET_DATA_VALID;
                        reg_data_valid <= 1'b1;
                    end
                end
                REG_SET_DATA_VALID : begin
                    if (rom_read_done) begin
                        rrsm_cs <= ADDRESS_READ;
                        reg_data_valid <= 1'b0;
                    end
                end
                END_RRSM :
                    rrsm_cs <= END_RRSM;
            endcase
        end
    end
    
    // rom_addr
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            rom_addr <= 8'd0;
        end else begin
            if (rrsm_cs == ADDRESS_READ) // Data
                rom_addr <= rom_addr + 8'd1;
            else if (rrsm_cs == REG_SET_DATA_VALID && rom_read_done) // Address
                rom_addr <= rom_addr + 8'd1;
        end
    end
    
    // AXI4 Lite Master Address
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            reg_addr <= 32'd0;
        end else begin
            if (rrsm_cs == DATA_READ)
                reg_addr <= rom_dout;
        end
    end
    assign M_AXI_AWADDR = reg_addr;
    
    // AXI4 Lite Master WDATA
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            reg_data <= 32'd0;
        end else begin
            if (rrsm_cs == REG_SET_DATA_VALID)
                reg_data <= rom_dout;
        end
    end
    assign M_AXI_WDATA = reg_data;
    
    // AXI Lite Master Address State Machine
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            addr_cs <= IDLE_ADDR;
            awvalid <= 1'b0;
        end else begin
            case (addr_cs)
                IDLE_ADDR :
                    if (rrsm_cs == REG_SET_DATA_VALID) begin
                        addr_cs <= AWVALID_ASSERT;
                        awvalid <= 1'b1;
                    end
                AWVALID_ASSERT :
                    if (M_AXI_AWREADY) begin
                        addr_cs <= AWVALID_HOLD_OFF;
                        awvalid <= 1'b0;
                    end
                AWVALID_HOLD_OFF :
                    if (rrsm_cs != REG_SET_DATA_VALID)
                        addr_cs <= IDLE_ADDR;
            endcase
        end
    end
    assign M_AXI_AWVALID = awvalid;
    
    // AXI Lite Master Data State Machine
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            data_cs <= IDLE_DATA;
            wvalid <= 1'b0;
        end else begin
            case (data_cs)
                IDLE_DATA : begin
                    if (rrsm_cs == REG_SET_DATA_VALID) begin
                        data_cs <= WVALID_ASSERT;
                        wvalid <= 1'b1;
                    end
                end
                WVALID_ASSERT :
                    if (M_AXI_WREADY) begin
                        wvalid <= 1'b0;
                        data_cs <= WVALID_HOLD_OFF;
                    end
                WVALID_HOLD_OFF : begin
                    if (addr_cs == AWVALID_HOLD_OFF && rrsm_cs != REG_SET_DATA_VALID)
                        data_cs <= IDLE_DATA;
                end
            endcase
        end
    end
    assign M_AXI_WVALID = wvalid;
    
    // bready State Machine
    always @(posedge M_AXI_ACLK) begin
        if (reset) begin
            resp_cs <= IDLE_RESP;
            bready <= 1'b0;
            rom_read_done <= 1'b0;
        end else begin
            case (resp_cs)
                IDLE_RESP : begin
                    rom_read_done <= 1'b0;
                    if (M_AXI_WREADY && data_cs == WVALID_ASSERT) begin
                        resp_cs <= BREADY_ASSERT;
                        bready <= 1'b1;
                    end
                end
                BREADY_ASSERT :
                    if (M_AXI_BVALID) begin
                        resp_cs <= IDLE_RESP;
                        bready <= 1'b0;
                        rom_read_done <= 1'b1;
                    end
            endcase
        end
    end
    assign M_AXI_BREADY = bready;
    
endmodule

`default_nettype wire

  1. 2015年03月12日 05:39 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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