FPGAの部屋 2012年03月13日
FC2ブログ

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

FPGAの部屋

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

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

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする6(BFMシミュレーション4)”でデータ転送中にランダムなWaitを挟む機能をBFMに追加した。

今度は、OVLの様なチェッカを組み込む。OVLの機能の概略は、”OVL(Open Verification Library)を試してみる7(OVLチェッカの概要)”を参照のこと。
今回は、ovl_increment、ovl_handshake、ovl_never を使用する。

ovl_incrementは、バーストデータが+1されるのを監視する。ovl_handshake は、S_AXI_AWVALIDとS_AXI_AWREADY、S_AXI_ARVALIDとS_AXI_ARREADYの間の関係を監視する。ovl_never は、S_AXI_AWREADYとその他の信号の関係、S_AXI_ARREADYとその他の信号の間の関係を監視する。

ovl_increment は、データが+1 されるのを監視するので、バースト・データ転送の前にリセットをかけて、その後のデータが +1 されるのを確認しようとした。しかし、リセットが効かないというか、リセットしても、すべて通してチェックされるようで、データ転送の最初のデータでエラーが出てしまった。下にエラーメッセージを示す。

OVL_ERROR : OVL_INCREMENT : Error: Write data has not been incremented : Test expression is increased by a value other than specified : severity 1 : time 945000 : CDC_axi_slave_tb.OVLi.wr_data_check.ovl_error_t
OVL_ERROR : OVL_INCREMENT : Error: Read data has not been incremented : Test expression is increased by a value other than specified : severity 1 : time 1045000 : CDC_axi_slave_tb.OVLi.rd_data_check.ovl_error_t
OVL_ERROR : OVL_INCREMENT : Error: Write data has not been incremented : Test expression is increased by a value other than specified : severity 1 : time 1105000 : CDC_axi_slave_tb.OVLi.wr_data_check.ovl_error_t
OVL_ERROR : OVL_INCREMENT : Error: Write data has not been incremented : Test expression is increased by a value other than specified : severity 1 : time 1185000 : CDC_axi_slave_tb.OVLi.wr_data_check.ovl_error_t


これを回避するには、Writeするデータを最初のデータの +1 にするしか無いようなので、後で修正する。

ovl_handshake は、req_dropを0にして、reqが複数クロックアサートされてもエラーにならないようだ。max_ack_cycle などを指定しないと動かないようだ。一応、min_ack_cycle に1を、max_ack_cycle に32を設定した。

ovl_never は、普通に動作しているようだ。エラー条件を設定して、エラーになることを確認した。

チェッカ、OVL_Checker.v を下に示す。

2012/10/25:修正、BFMにAXI非標準の部分があったので、後で書き直しています。OVL Checker もそれに合わせて修正しています。OVL Checker の修正後のファイルは、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.4(OVLチェッカのVerilog コード)”を見てください。下のファイルは修正前です)

// OVL_Checker.v

`default_nettype none

`timescale 100ps / 1ps

`include "std_ovl_defines.h"

module OVL_Checker (
    input    wire    ACLK,
    input    wire    ARESETN,

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

    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
);

    wire [`OVL_FIRE_WIDTH-1:0] fire_wr_data, fire_rd_data;
    wire [`OVL_FIRE_WIDTH-1:0] fire_aw_hcheck, fire_ar_hcheck;
    wire [`OVL_FIRE_WIDTH-1:0] fire_aw_never, fire_ar_never;
    reg        [7:0]    countw, countr;
    
    parameter    idle_wts =        3'b001,
                wr_data_tran =    3'b010,
                wr_resp_tran =    3'b100;
    reg    [2:0]    wr_tran_cs;
    
    parameter    idle_rts =        1'b0,
                rd_data_tran =    1'b1;
    reg    rd_trans_cs;
    
    
    // Wirte Transaction データが+1されていることをチェックする(BFM Check)
    ovl_increment #(
        `OVL_ERROR,            // severity_level
        32,                        // width
        1,                        // value
        `OVL_ASSERT,            // property_type
        "Error: Write data has not been incremented", // msg
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) wr_data_check (
        ACLK,                    // clock
        ~ARESETN | (S_AXI_AWVALID & S_AXI_AWREADY),    // reset, Write のアドレス転送でリセット
        S_AXI_WVALID & S_AXI_WREADY,                    // enable
        S_AXI_WDATA,            // test_expr
        fire_wr_data            // fire    parameter
    );
    
    // Read Transaction データが+1されていることをチェックする(BFM Check)
    ovl_increment #(
        `OVL_ERROR,            // severity_level
        32,                        // width
        1,                        // value
        `OVL_ASSERT,            // property_type
        "Error: Read data has not been incremented", // msg
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) rd_data_check (
        ACLK,                    // clock
        ~ARESETN | (S_AXI_ARVALID & S_AXI_ARREADY),    // reset, Read のアドレス転送でリセット
        S_AXI_RVALID & S_AXI_RREADY,                    // enable
        S_AXI_RDATA,            // test_expr
        fire_rd_data            // fire    parameter
    );
    
    
    // S_AXI_AWVALID とS_AXI_AWREADY のハンドシェークのテスト
    ovl_handshake #(
        `OVL_ERROR,            // severity_level
        1,                    // min_ack_cycle
        32,                    // max_ack_cycle
        1,                    // req_drop
        1,                    // deassert_count
        1,                    // max_ack_length
        `OVL_ASSERT,        // property_type
        "Error: Handshake Error of S_AXI_AWREADY and S_AXI_AWVALID",
        `OVL_COVER_DEFAULT,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_LOW,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) aw_handshake_check (
        ACLK,                    // clock
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWVALID,            // req
        S_AXI_AWREADY,            // ack
        fire_aw_hcheck            // fire parameter
    );
    
    // S_AXI_ARVALID とS_AXI_ARREADY のハンドシェークのテスト
    ovl_handshake #(
        `OVL_ERROR,            // severity_level
        1,                    // min_ack_cycle
        32,                    // max_ack_cycle
        1,                    // req_drop
        1,                    // deassert_count
        1,                    // max_ack_length
        `OVL_ASSERT,        // property_type
        "Error: Handshake Error of S_AXI_ARREADY and S_AXI_ARVALID",
        `OVL_COVER_DEFAULT,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_LOW,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) ar_handshake_check (
        ACLK,                    // clock
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_ARVALID,            // req
        S_AXI_ARREADY,            // ack
        fire_ar_hcheck            // fire parameter
    );
    
    // Write, S_AXI_AWREADY がアサートされるときは、S_AXI_WVALID, S_AXI_WREADY, S_AXI_WLAST, S_AXI_BVALID, S_AXI_BREADY はアサートされない。
    ovl_never #(
        `OVL_ERROR,                // severity_level
        `OVL_ASSERT,            // property_type
        "Write, Assert Error of S_AXI_AWREADY",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) aw_never_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWREADY & (S_AXI_WVALID | S_AXI_WREADY | S_AXI_WLAST | S_AXI_BVALID | S_AXI_BREADY),
        fire_aw_never
    );
    
    // Read, S_AXI_RREADY がアサートされるときは、 S_AXI_RVALID, S_AXI_RREADY, S_AXI_RLAST はアサートされない
    ovl_never #(
        `OVL_ERROR,                // severity_level
        `OVL_ASSERT,            // property_type
        "Read, Assert Error of S_AXI_RREADY",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) ar_never_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_ARREADY & (S_AXI_RVALID | S_AXI_RREADY | S_AXI_RLAST),
        fire_ar_never
    );
    
    // Write の転送数をカウントして、 S_AXI_WLAST の出力を確認するアサーション
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            countw <= 0;
        else begin
            if (S_AXI_AWVALID & S_AXI_AWREADY) begin // countw へロード
                countw <= S_AXI_AWLEN;
            end else if (S_AXI_WVALID & S_AXI_WREADY) begin // データ転送
                if (countw==0) begin // データ転送終了
                    if (~S_AXI_WLAST) begin // countw==0 でS_AXI_WLASTが立たない
                        $display("%m: at time %t Error: countw==0 でS_AXI_WLASTが立たない",$time);
                    end
                end
            end
        end
    end
    
    // Read の転送数をカウントして、 S_AXI_RLAST の出力を確認するアサーション
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            countr <= 0;
        else begin
            if (S_AXI_ARVALID & S_AXI_ARREADY) begin // countw へロード
                countr <= S_AXI_ARLEN;
            end else if (S_AXI_RVALID & S_AXI_RREADY) begin // データ転送
                if (countr==0) begin // データ転送終了
                    if (~S_AXI_RLAST) begin // countw==0 でS_AXI_WLASTが立たない
                        $display("%m: at time %t Error: countr==0 でS_AXI_WLASTが立たない",$time);
                    end
                end
            end
        end
    end
    
    // Write 動作用ステートマシン
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            wr_tran_cs <= idle_wts;
        else begin
            case (wr_tran_cs)
                idle_wts :
                    if (S_AXI_AWREADY & (S_AXI_WVALID | S_AXI_WREADY | S_AXI_WLAST | S_AXI_BVALID | S_AXI_BREADY)) // エラー
                        $display("%m: at time %t S_AXI_AWREADY がアサートされた時に、その他のVALID, READY信号がアサートされた",$time);
                    else if (S_AXI_AWVALID & S_AXI_AWREADY) // アドレス転送終了
                        wr_tran_cs <= wr_data_tran;
                wr_data_tran :
                    if (S_AXI_AWREADY | S_AXI_BVALID | S_AXI_BREADY) // エラー
                        $display("%m: at time %t Write データ転送中に、S_AXI_AWREADY | S_AXI_BVALID | S_AXI_BREADY がアサートされた",$time);
                    else if (S_AXI_WVALID & S_AXI_WREADY & S_AXI_WLAST) // データ転送終了
                        wr_tran_cs <= wr_resp_tran;
                wr_resp_tran :
                    if (S_AXI_AWREADY | S_AXI_WVALID | S_AXI_WREADY | S_AXI_WLAST) // エラー
                        $display("%m: at time %t Write Response Channel 転送時に関連しない信号がアサートされた",$time);
                    else if (S_AXI_BVALID & S_AXI_BREADY) // Write Response Channel 転送終了
                        wr_tran_cs <= idle_wts;
            endcase
        end
    end
    
    // Read 動作用ステートマシン
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            rd_trans_cs <= idle_rts;
        else begin
            case (rd_trans_cs)
                idle_rts :
                    if (S_AXI_ARREADY & (S_AXI_RVALID | S_AXI_RREADY | S_AXI_RLAST)) // エラー
                        $display("%m: at time %t S_AXI_ARREADY がアサートされた時に、その他のVALID, READY信号がアサートされた",$time);
                    else if (S_AXI_ARVALID & S_AXI_ARREADY) // アドレス転送終了
                        rd_trans_cs <= rd_data_tran;
                rd_data_tran :
                    if (S_AXI_ARREADY) // エラー
                        $display("%m: at time %t Read データ転送中に、S_AXI_ARREADY がアサートされた",$time);
                    else if (S_AXI_RVALID & S_AXI_RREADY & S_AXI_RLAST) // データ転送終了
                        rd_trans_cs <= idle_rts;
            endcase
        end
    end
                        
endmodule    

`default_nettype wire


CDC_axi_slave_tb.v はOVL_Checker.v への接続ポートだけを追加してある。追加分を下に示す。

    // OVL Checker
    OVL_Checker OVLi (
        .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), 
        .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)
    );


シミュレーション波形は以前と同じだが、Write波形の全景を下に示す。
CDC_axi_slave_14_120313.png

Read波形の全景を示す。(Write波形と時間軸は同じだ)
CDC_axi_slave_15_120313.png
  1. 2012年03月13日 20:27 |
  2. AXI4 Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0