FC2カウンター FPGAの部屋 キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする6(BFMシミュレーション4)
FC2ブログ

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

FPGAの部屋

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

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする6(BFMシミュレーション4)

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする5(BFMシミュレーション3)”の続き。

今回は、バーストWrite, バーストReadの最中にマスタから任意のWaitを入れる機能を実現してみた。どうやったかというと、$unsigned($random)で整数のランダム値を生成して、それを設定値+1で割った余りを使ってWait数を決めることにした。そうすると0からtask に設定した値のまでのWaitがランダムに入るはずだ。これで、マスタ側でWaitしてもAXI4バスのスレーブIPがきちんとデータを出せるかどうかを検証することができる。
下に示すtask の最後の数が最大のWait数になる。

MBFMi.AXI_Master_1Seq_Write(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 32'h12345678, 0, 2);
MBFMi.AXI_MASTER_WDC(32'h3333_4444, 4);
MBFMi.AXI_Master_1Seq_Read(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 3);


MBFMi.AXI_Master_1Seq_Writeでは、最大Wait数が2、MBFMi.AXI_MASTER_WDCでは最大Wait数が4、MBFMi.AXI_Master_1Seq_Readでは最大Wait数が3となる。0を入れれば、今まで通りにWait無しのデータ転送になる。
Writeの波形を下に示す。これは、”MBFMi.AXI_Master_1Seq_Write(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 32'h12345678, 0, 2);”の波形だ。
CDC_axi_slave_12_120308.png

余りランダムでない気もするが、Wait無しと2クロックWaitのWriteがあるのがわかると思う。

次に、Readの波形を下に示す。これは、”MBFMi.AXI_Master_1Seq_Read(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 3);”の波形だ。
CDC_axi_slave_13_120308.png

Readの方がランダムな気がする。Waitが入っているのがわかる。

現在の、AXI4バスMaster BFM (AXI4_Master_BFM.v) を下に貼っておく。

2012/10/25:修正、またまたAXI非標準の部分があったので、書き直しています。この下のBFMはAXI非標準のままにしてあります。AXI非標準部分の修正後のファイルは、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.3(AXI Master BFMのVerilogコード)”を見てください。)

// AXI4 bus Master Bus Fucntion Mode

`default_nettype none

`timescale 100ps / 1ps

module AXI4_Master_BFM #(
    parameter DELAY    = 10 )
(
    input    wire    ACLK,

    output reg [0:0] S_AXI_AWID = 0,
    output reg [31:0] S_AXI_AWADDR = 0,
    output reg [7:0] S_AXI_AWLEN = 0,
    output reg [2:0] S_AXI_AWSIZE = 0,
    output reg [1:0] S_AXI_AWBURST = 0,
    output reg [1:0] S_AXI_AWLOCK = 0,
    output reg [3:0] S_AXI_AWCACHE = 2,    // Normal Non-cacheable Non-bufferable
    output reg [2:0] S_AXI_AWPROT = 0,
    output reg [3:0] S_AXI_AWREGION = 0,
    output reg [3:0] S_AXI_AWQOS = 0,
    output reg [0:0] S_AXI_AWUSER = 0,
    output reg S_AXI_AWVALID = 0,
    output reg [0:0] S_AXI_WID = 0,
    output reg [31:0] S_AXI_WDATA = 0,
    output reg [3:0] S_AXI_WSTRB = 0,
    output reg S_AXI_WLAST = 0,
    output reg [0:0] S_AXI_WUSER = 0,
    output reg S_AXI_WVALID = 0,
    output reg S_AXI_BREADY = 0,
    output reg [0:0] S_AXI_ARID = 0,
    output reg [31:0] S_AXI_ARADDR = 0,
    output reg [7:0] S_AXI_ARLEN = 0,
    output reg [2:0] S_AXI_ARSIZE = 0,
    output reg [1:0] S_AXI_ARBURST = 0,
    output reg [1:0] S_AXI_ARLOCK = 0,
    output reg [3:0] S_AXI_ARCACHE = 2, // Normal Non-cacheable Non-bufferable
    output reg [2:0] S_AXI_ARPROT = 0,
    output reg [3:0] S_AXI_ARREGION = 0,
    output reg [3:0] S_AXI_ARQOS = 0,
    output reg [0:0] S_AXI_ARUSER = 0,
    output reg S_AXI_ARVALID = 0,
    output reg S_AXI_RREADY = 0,

    input wire S_AXI_AWREADY,
    input wire S_AXI_WREADY,
    input wire [0:0] S_AXI_BID,
    input wire [1:0] S_AXI_BRESP,
    input wire [0:0] S_AXI_BUSER,
    input wire S_AXI_BVALID,
    input wire S_AXI_ARREADY,
    input wire [0:0] S_AXI_RID,
    input wire [31:0] S_AXI_RDATA,
    input wire [1:0] S_AXI_RRESP,
    input wire S_AXI_RLAST,
    input wire [0:0] S_AXI_RUSER,
    input wire S_AXI_RVALID
);

    reg     [7:0]    awlen_hold = 0;
    reg     [0:0]    wid_hold = 0;
    reg     axi_w_transaction_active = 0;
    reg     axi_r_transaction_active = 0;
    reg     [7:0]    arlen_hold = 0;

    // Write Channel
    task AXI_Master_1Seq_Write;    // Write Address, Write Data, Write Response をシーケンシャルにオーバーラップせずに行う。
        input    [0:0]    awid;
        input    [31:0]    awaddr;
        input    [7:0]    awlen;
        input    [2:0]    awsize;
        input    [1:0]    awburst;
        input    [31:0]    wdata;
        input    [7:0]    wait_clk_bready;
        input    [7:0]    wmax_wait;
        begin
            AXI_MASTER_WAC(awid, awaddr, awlen, awsize, awburst);
            AXI_MASTER_WDC(wdata, wmax_wait);
            AXI_MASTER_WRC(wait_clk_bready);
        end
    endtask
    
    // Write Address Channel
    task AXI_MASTER_WAC;
        input    [0:0]    awid;
        input    [31:0]    awaddr;
        input    [7:0]    awlen;
        input    [2:0]    awsize;
        input    [1:0]    awburst;
        begin
            S_AXI_AWID        = awid;
            S_AXI_AWADDR    = awaddr;
            S_AXI_AWLEN        = awlen;
            S_AXI_AWSIZE    = awsize;
            S_AXI_AWBURST    = awburst;
            S_AXI_AWVALID    = 1'b1;

            if (axi_w_transaction_active == 1'b0) begin // AXI Write トランザクションが開始されている場合は戻る
                awlen_hold        = awlen; // Write Data Channel のためにバースト数を取っておく
                @(posedge ACLK);    // 次のクロックへ
                
                while (~S_AXI_AWREADY) begin    // S_AXI_AWREADY が1になるまで待つ
                    #DELAY;
                    @(posedge ACLK);    // 次のクロックへ
                end
                
                #DELAY;
                S_AXI_AWID         = 0;
                S_AXI_AWADDR    = 0;
                S_AXI_AWLEN     = 0;
                S_AXI_AWSIZE     = 0;
                S_AXI_AWBURST     = 0;
                S_AXI_AWVALID     = 1'b0;
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
                axi_w_transaction_active = 1'b1; // AXIトランザクション開始
            end
        end
    endtask
    
    // Write Data Channel
    task AXI_MASTER_WDC;    // WDATA は+1する
    // とりあえず、WSTRBはオール1にする
        input    [31:0]    wdata;
        input    [7:0]    wmax_wait;    // Write時の最大wait数
        integer    i, j, val;
        begin
            i = 0; j = 0;
            S_AXI_WSTRB = 4'b1111;
            
            while (i<=awlen_hold) begin
                if (wmax_wait == 0) // wmax_wait が0の時は$random を実行しない
                    val = 0;
                else
                    val = $unsigned($random) % (wmax_wait+1);

                if (val == 0) // waitなし
                    S_AXI_WVALID = 1'b1;
                else begin // waitあり
                    S_AXI_WVALID = 1'b0;
                    for (j=0; j<wmax_wait; j=j+1) begin
                        @(posedge ACLK);    // 次のクロックへ
                        #DELAY;
                    end
                    S_AXI_WVALID = 1'b1; // wait終了
                end
                    
                if (i == awlen_hold)
                    S_AXI_WLAST = 1'b1;
                else
                    S_AXI_WLAST = 1'b0;
                S_AXI_WDATA = wdata;
                wdata = wdata + 1;
                
                @(posedge ACLK);    // 次のクロックへ
                
                while (~S_AXI_WREADY) begin    // S_AXI_WREADY が0の時は1になるまで待つ
                    #DELAY;
                    @(posedge ACLK);    // 次のクロックへ
                end
                #DELAY;
                
                i = i + 1;
            end
            S_AXI_WVALID = 1'b0;
            S_AXI_WLAST = 1'b0;
            S_AXI_WSTRB = 4'b0000;
        end
    endtask
    
    // Write Response Channel
    task AXI_MASTER_WRC;    // wait_clk_bready
        input    [7:0]    wait_clk_bready;
        integer    i;
        begin
            for (i=0; i<wait_clk_bready; i=i+1) begin
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end
            
            S_AXI_BREADY = 1'b1;
            
                
            @(posedge ACLK);    // 次のクロックへ
            
            while (~S_AXI_BVALID) begin // S_AXI_BVALID が1になるまでWait
                #DELAY;
                @(posedge ACLK);    // 次のクロックへ
            end
            #DELAY;
            
            S_AXI_BREADY = 1'b0;
            
            axi_w_transaction_active = 1'b0; // AXIトランザクション終了
        end
    endtask 
    
    // Read Channel
    task AXI_Master_1Seq_Read; // Read Address, Read Data をシーケンシャルに行う。
        input    [0:0]    arid;
        input    [31:0]    araddr;
        input    [7:0]    arlen;
        input    [2:0]    arsize;
        input    [1:0]    arburst;
        input    [7:0]    rmax_wait;    // Read時の最大wait数
        begin
            AXI_MASTER_RAC(arid, araddr, arlen, arsize, arburst);
            AXI_MASTER_RDC(rmax_wait);
        end
    endtask

    // Read Address Channel    
    task AXI_MASTER_RAC;
        input    [0:0]    arid;
        input    [31:0]    araddr;
        input    [7:0]    arlen;
        input    [2:0]    arsize;
        input    [1:0]    arburst;
        begin
            S_AXI_ARID         = arid;
            S_AXI_ARADDR    = araddr;
            S_AXI_ARLEN        = arlen;
            S_AXI_ARSIZE    = arsize;
            S_AXI_ARBURST    = arburst;
            S_AXI_ARVALID     = 1'b1;
            
            if (axi_r_transaction_active == 1'b0) begin // AXI Read トランザクションが開始されている場合は戻る
                arlen_hold    =arlen; // Read Data Channel のためにバースト数を取っておく
                @(posedge ACLK);    // 次のクロックへ
                
                while (~S_AXI_ARREADY) begin    // S_AXI_ARREADY が1になるまで待つ
                    #DELAY;
                    @(posedge ACLK);    // 次のクロックへ
                end
                
                #DELAY;
                S_AXI_ARID         = 0;
                S_AXI_ARADDR    = 0;
                S_AXI_ARLEN     = 0;
                S_AXI_ARSIZE     = 0;
                S_AXI_ARBURST     = 0;
                S_AXI_ARVALID     = 1'b0;
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
                axi_r_transaction_active = 1'b1; // AXIトランザクション開始
            end
        end
    endtask
    
    // Read Data Channel
    task AXI_MASTER_RDC; // S_AXI_RLAST がアサートされるまでS_AXI_RREADY をアサートする
        input    [7:0]    rmax_wait;    // Read時の最大wait数
        integer i, val;
        begin    
            while (~(S_AXI_RLAST & S_AXI_RVALID & S_AXI_RREADY)) begin // S_AXI_RLAST & S_AXI_RVALID & S_AXI_RREADY で終了
                if (rmax_wait == 0) begin // rmax_wait が0の時は$random を実行しない
                    val = 0;
                    S_AXI_RREADY = 1'b1;
                end else begin
                    val = $unsigned($random) % (rmax_wait+1);
                    if (val == 0)
                        S_AXI_RREADY = 1'b1;
                    else
                        S_AXI_RREADY = 1'b0;
                end
                #DELAY;
                
                for (i=0; i<val; i=i+1) begin // ランダム値でWait、val=0の時はスキップ
                    @(posedge ACLK);    // 次のクロックへ
                    #DELAY;
                end
                
                S_AXI_RREADY = 1'b1;
                @(posedge ACLK);    // 次のクロックへ
                while (~S_AXI_RVALID) begin // S_AXI_RVALID が1になるまでWait
                    #DELAY;
                    @(posedge ACLK);    // 次のクロックへ
                end
                #DELAY;
            end
            #DELAY;
            
            S_AXI_RREADY = 1'b0;
            axi_r_transaction_active = 1'b0; // AXIトランザクション終了
        end
    endtask
    
endmodule

`default_nettype wire


次に、テストベンチ (CDC_axi_slave_tb.v) を貼っておく。

// CDC_axi_slave_tb.v

`default_nettype none

`timescale 100ps / 1ps

module CDC_axi_slave_tb;
    
    parameter DELAY    = 10;
    
    parameter    ASIZE_BT_4    = 3'd2;    // 32 bit width
    parameter    ASIZE_BT_2 = 3'd1;    // 16 bit width
    parameter    ASIZE_BT_1 = 3'd0;    // 8 bit width
    
    parameter    ABURST_FIXED    = 2'd0;
    parameter    ABURST_INCR    = 2'd1;
    parameter    ABURST_WRAP    = 2'd2;
    
    parameter    BRESP_OKAY        = 2'b00;
    parameter    BRESP_EXOKAY    = 2'b01;
    parameter    BRESP_SLVERR    = 2'b10;
    parameter    BRESP_DECERR    = 2'b11;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire [0:0] S_AXI_AWID;
    wire [31:0] S_AXI_AWADDR;
    wire [7:0] S_AXI_AWLEN;
    wire [2:0] S_AXI_AWSIZE;
    wire [1:0] S_AXI_AWBURST;
    wire [1:0] S_AXI_AWLOCK;
    wire [3:0] S_AXI_AWCACHE;
    wire [2:0] S_AXI_AWPROT;
    wire [3:0] S_AXI_AWREGION;
    wire [3:0] S_AXI_AWQOS;
    wire [0:0] S_AXI_AWUSER;
    wire S_AXI_AWVALID;
    wire [0:0] S_AXI_WID;
    wire [31:0] S_AXI_WDATA;
    wire [3:0] S_AXI_WSTRB;
    wire S_AXI_WLAST;
    wire [0:0] S_AXI_WUSER;
    wire S_AXI_WVALID;
    wire S_AXI_BREADY;
    wire [0:0] S_AXI_ARID;
    wire [31:0] S_AXI_ARADDR;
    wire [7:0] S_AXI_ARLEN;
    wire [2:0] S_AXI_ARSIZE;
    wire [1:0] S_AXI_ARBURST;
    wire [1:0] S_AXI_ARLOCK;
    wire [3:0] S_AXI_ARCACHE;
    wire [2:0] S_AXI_ARPROT;
    wire [3:0] S_AXI_ARREGION;
    wire [3:0] S_AXI_ARQOS;
    wire [0:0] S_AXI_ARUSER;
    wire S_AXI_ARVALID;
    wire S_AXI_RREADY;
    wire pixclk;

    // Outputs
    reg     S_AXI_AWREADY;
    reg     S_AXI_WREADY;
    reg     [0:0] S_AXI_BID;
    reg     [1:0] S_AXI_BRESP;
    wire     [0:0] S_AXI_BUSER = 0;
    reg     S_AXI_BVALID;
    reg     S_AXI_ARREADY;
    reg     [0:0] S_AXI_RID;
    reg     [31:0] S_AXI_RDATA;
    reg     [1:0] S_AXI_RRESP;
    reg     S_AXI_RLAST;
    wire     [0:0] S_AXI_RUSER = 0;
    reg     S_AXI_RVALID;
    wire TMDS_tx_clk_p;
    wire TMDS_tx_clk_n;
    wire TMDS_tx_2_G_p;
    wire TMDS_tx_2_G_n;
    wire TMDS_tx_1_R_p;
    wire TMDS_tx_1_R_n;
    wire TMDS_tx_0_B_p;
    wire TMDS_tx_0_B_n;

    wire S_AXI_AWREADY_d;
    wire S_AXI_WREADY_d;
    wire [0:0]    S_AXI_BID_d;
    wire [1:0]    S_AXI_BRESP_d;
    wire S_AXI_BVALID_d;
    wire S_AXI_ARREADY_d;
    wire [0:0]    S_AXI_RID_d;
    wire [31:0]    S_AXI_RDATA_d;
    wire [1:0]    S_AXI_RRESP_d;
    wire S_AXI_RLAST_d;
    wire S_AXI_RVALID_d;
    
    // Instantiate the Unit Under Test (UUT)
    CDC_axi_slave uut (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWID(S_AXI_AWID), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWLEN(S_AXI_AWLEN), 
        .S_AXI_AWSIZE(S_AXI_AWSIZE), 
        .S_AXI_AWBURST(S_AXI_AWBURST), 
        .S_AXI_AWLOCK(S_AXI_AWLOCK), 
        .S_AXI_AWCACHE(S_AXI_AWCACHE), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(S_AXI_AWQOS), 
        .S_AXI_AWUSER(S_AXI_AWUSER), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY_d), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WLAST(S_AXI_WLAST), 
        .S_AXI_WUSER(S_AXI_WUSER), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY_d), 
        .S_AXI_BID(S_AXI_BID_d), 
        .S_AXI_BRESP(S_AXI_BRESP_d), 
        .S_AXI_BUSER(S_AXI_BUSER), 
        .S_AXI_BVALID(S_AXI_BVALID_d), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARID(S_AXI_ARID), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARLEN(S_AXI_ARLEN), 
        .S_AXI_ARSIZE(S_AXI_ARSIZE), 
        .S_AXI_ARBURST(S_AXI_ARBURST), 
        .S_AXI_ARLOCK(S_AXI_ARLOCK), 
        .S_AXI_ARCACHE(S_AXI_ARCACHE), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(S_AXI_ARQOS), 
        .S_AXI_ARUSER(S_AXI_ARUSER), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY_d), 
        .S_AXI_RID(S_AXI_RID_d), 
        .S_AXI_RDATA(S_AXI_RDATA_d), 
        .S_AXI_RRESP(S_AXI_RRESP_d), 
        .S_AXI_RLAST(S_AXI_RLAST_d), 
        .S_AXI_RUSER(S_AXI_RUSER), 
        .S_AXI_RVALID(S_AXI_RVALID_d), 
        .S_AXI_RREADY(S_AXI_RREADY), 
        .pixclk(pixclk), 
        .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 @* S_AXI_AWREADY <= #DELAY S_AXI_AWREADY_d;
    always @* S_AXI_WREADY <= #DELAY S_AXI_WREADY_d;
    always @* S_AXI_BID <= #DELAY S_AXI_BID_d;
    always @* S_AXI_BRESP <= #DELAY S_AXI_BRESP_d;
    always @* S_AXI_BVALID <= #DELAY S_AXI_BVALID_d;
    always @* S_AXI_ARREADY <= #DELAY S_AXI_ARREADY_d;
    always @* S_AXI_RID <= #DELAY S_AXI_RID_d;
    always @* S_AXI_RDATA <= #DELAY S_AXI_RDATA_d;
    always @* S_AXI_RRESP <= #DELAY S_AXI_RRESP_d;
    always @* S_AXI_RLAST <= #DELAY S_AXI_RLAST_d;
    always @* S_AXI_RVALID <= #DELAY S_AXI_RVALID_d;
    
    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    clk_gen #(
        .CLK_PERIOD(250),    // 25nsec, 40MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) PIXCLKi (
        .clk_out(pixclk)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );
    
    // AXI4_BFM のインスタンス
    AXI4_Master_BFM #(.DELAY(DELAY)) MBFMi(
        .ACLK(ACLK), 
        .S_AXI_AWID(S_AXI_AWID), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWLEN(S_AXI_AWLEN), 
        .S_AXI_AWSIZE(S_AXI_AWSIZE), 
        .S_AXI_AWBURST(S_AXI_AWBURST), 
        .S_AXI_AWLOCK(S_AXI_AWLOCK), 
        .S_AXI_AWCACHE(S_AXI_AWCACHE), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(S_AXI_AWQOS), 
        .S_AXI_AWUSER(S_AXI_AWUSER), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WLAST(S_AXI_WLAST), 
        .S_AXI_WUSER(S_AXI_WUSER), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY), 
        .S_AXI_BID(S_AXI_BID), 
        .S_AXI_BRESP(S_AXI_BRESP), 
        .S_AXI_BUSER(S_AXI_BUSER), 
        .S_AXI_BVALID(S_AXI_BVALID), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARID(S_AXI_ARID), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARLEN(S_AXI_ARLEN), 
        .S_AXI_ARSIZE(S_AXI_ARSIZE), 
        .S_AXI_ARBURST(S_AXI_ARBURST), 
        .S_AXI_ARLOCK(S_AXI_ARLOCK), 
        .S_AXI_ARCACHE(S_AXI_ARCACHE), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(S_AXI_ARQOS), 
        .S_AXI_ARUSER(S_AXI_ARUSER), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY), 
        .S_AXI_RID(S_AXI_RID), 
        .S_AXI_RDATA(S_AXI_RDATA), 
        .S_AXI_RRESP(S_AXI_RRESP), 
        .S_AXI_RLAST(S_AXI_RLAST), 
        .S_AXI_RUSER(S_AXI_RUSER), 
        .S_AXI_RVALID(S_AXI_RVALID), 
        .S_AXI_RREADY(S_AXI_RREADY)
    );
    
    // test
    
    // Write Channel
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked
        
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        
        MBFMi.AXI_Master_1Seq_Write(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 32'h12345678, 0, 2);
        MBFMi.AXI_Master_1Seq_Write(0, 32'h200, 8'd0, ASIZE_BT_4, ABURST_INCR, 32'h11223344, 1, 0);
        
        // アドレス転送のオーバーラップのサンプル
        // オーバーラップ後にもう一度、2度目のWrite Address Channel の転送を行う。
        MBFMi.AXI_MASTER_WAC(0, 32'h300, 8'd0, ASIZE_BT_4, ABURST_INCR);
        MBFMi.AXI_MASTER_WAC(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR);
        MBFMi.AXI_MASTER_WDC(32'h1111_2222, 2);
        MBFMi.AXI_MASTER_WRC(0);
        MBFMi.AXI_MASTER_WAC(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR);
        MBFMi.AXI_MASTER_WDC(32'h3333_4444, 4);
        MBFMi.AXI_MASTER_WRC(0);
    end
    
    // Read Channel
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked
        
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        
        MBFMi.AXI_Master_1Seq_Read(0, 32'h100, 8'd4, ASIZE_BT_4, ABURST_INCR, 3);
        MBFMi.AXI_Master_1Seq_Read(0, 32'h200, 8'd0, ASIZE_BT_4, ABURST_INCR, 4);
        
    end
    
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


これで、ランダムにWaitするデータ転送が実現できた。次は、Write, Read Transaction をfor ループで何十回も回せば、アドレス転送(AW... AR...)もWaitするし、データ転送もランダムにWaitするので、いろいろな転送パターンを試せる。これを目で見て良否を判断するのは大変で、やりたくない。そこで、OVLチェッカを付けて、自動的に良否を判定したい。エラーの時はエラー表示を出して、発火信号(Fire) を監視しようと思う。

OVL(Open Verification Language? Open Verification Library?)は、Accellera社から無料でダウンロードして使用することができる検証用ライブラリです。今回ダウンロードしたら、Ver. 2.6 になっていました。OVLを使用して、アサーションを使用した検証を行います。
  1. 2012年03月08日 05:42 |
  2. AXI4 Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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