FC2カウンター FPGAの部屋 2012年10月25日
FC2ブログ

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

FPGAの部屋

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

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.4(OVLチェッカのVerilog コード)

前の記事は、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.1(BFMシミュレーション7)”だが、全体の関連は、”AXI4 Slave IPの作製”を参照のこと。

OVLチェッカはOVL(Open Verification Library)を使用して、AXIバスの信号が規格から外れていないか?をチェックするチェッカだ。OVLだけでなく、Verilogコードも書いてチェックしてあるが、まだまだルールが足りないと思っている。OVLでもどのようにチェッカを使うか迷う場面が少なくない。汎用性を持たせようと思うと、並列のトランザクションに対応する必要がある。それにはまだ対応していないが、OVLチェッカだけでは難しいのではないか?と考えている。例えば、AWVALIDとAWREADYの組みとWVALID, WREADY, WLASTの組みのカウント数が合っているか?をチェックするチェッカが必要なのではないか?と思っている。

現在のOVL_Checker.v を下に貼っておく。

// OVL_Checker.v
// 2012/10/25:書き込みトランザクションの時に、MasterがAWREADYを待って、WVALIDをアサートしていけないというルールがあったので、修正した。
//

`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_awvalid_cont, fire_wd_sig_assert;
    wire [`OVL_FIRE_WIDTH-1:0] 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_AWVALIDがディアサートされる
    ovl_transition #(
        `OVL_ERROR,                // severity_level
        1,                        // width
        `OVL_ASSERT,            // property_type
        "Error : Assert of S_AXI_AWVALID",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) awvalid_cont_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWVALID,            // test_expr
        S_AXI_AWREADY & S_AXI_AWVALID,    // start_state
        ~S_AXI_AWVALID,            // next_state
        fire_awvalid_cont
    );
    
    // Write, S_AXI_WVALID, S_AXI_WLAST, S_AXI_WREADYがアサートされるとき、次のクロックで、それらの信号がディアサートされる
    ovl_transition #(
        `OVL_ERROR,                // severity_level
        1,                        // width
        `OVL_ASSERT,            // property_type
        "Error : Assert of S_AXI_WVALID or S_AXI_WLAST or S_AXI_WREADY",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) wd_sig_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWVALID,            // test_expr
        S_AXI_WVALID & S_AXI_WLAST & S_AXI_WREADY,    // start_state
        ~(S_AXI_WVALID | S_AXI_WLAST | S_AXI_WREADY),            // next_state
        fire_wd_sig_assert
    );
    
    // 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_BREADY)) // エラー
                        $display("%m: at time %t S_AXI_AWREADY がアサートされた時に、BREADY信号がアサートされた",$time);
                    else if (S_AXI_AWVALID & S_AXI_AWREADY) // アドレス転送終了
                        wr_tran_cs <= wr_data_tran;
                wr_data_tran :
                    if (S_AXI_BREADY) // エラー
                        $display("%m: at time %t Write データ転送中に、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



OVLは実行オプションが重要なので、コマンドラインでのコマンドを下に示す。

Command Line: fuse -intstyle ise -incremental -i K:/HDL/OVL/std_ovl_v2p6 -d OVL_VERILOG -d OVL_ASSERT_ON -d OVL_FINISH_OFF -lib unisims_ver -lib unimacro_ver -lib xilinxcorelib_ver -lib secureip -o H:/HDL/FndtnISEWork/Spartan6/Atlys/Atlys_XPS_CDC_SVGA_141/pcores/cdc_axi_slave_v1_00_a/CDC_axi_slave/CDC_axi_slave_tb_isim_beh.exe -prj H:/HDL/FndtnISEWork/Spartan6/Atlys/Atlys_XPS_CDC_SVGA_141/pcores/cdc_axi_slave_v1_00_a/CDC_axi_slave/CDC_axi_slave_tb_beh.prj work.CDC_axi_slave_tb work.glbl {-L accellera_ovl_vlog=K:\HDL\Xilinx\13.4\ISE_DS\ISE\verilog\hdp\nt\accellera_ovl_vlog}
Running: K:\HDL\Xilinx\14.1\ISE_DS\ISE\bin\nt\unwrapped\fuse.exe -intstyle ise -incremental -i K:/HDL/OVL/std_ovl_v2p6 -d OVL_VERILOG -d OVL_ASSERT_ON -d OVL_FINISH_OFF -lib unisims_ver -lib unimacro_ver -lib xilinxcorelib_ver -lib secureip -o H:/HDL/FndtnISEWork/Spartan6/Atlys/Atlys_XPS_CDC_SVGA_141/pcores/cdc_axi_slave_v1_00_a/CDC_axi_slave/CDC_axi_slave_tb_isim_beh.exe -prj H:/HDL/FndtnISEWork/Spartan6/Atlys/Atlys_XPS_CDC_SVGA_141/pcores/cdc_axi_slave_v1_00_a/CDC_axi_slave/CDC_axi_slave_tb_beh.prj work.CDC_axi_slave_tb work.glbl -L accellera_ovl_vlog=K:\HDL\Xilinx\13.4\ISE_DS\ISE\verilog\hdp\nt\accellera_ovl_vlog

  1. 2012年10月25日 05:59 |
  2. AX4 Lite Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.3(AXI Master BFMのVerilogコード)

前の記事は、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.1(BFMシミュレーション7)”だが、全体の関連は、”AXI4 Slave IPの作製”を参照のこと。

今回はAXI Master BFMを貼っておく。AXI Master BFMと言っても、汎用的に使えるものではなく、トランザクションの並列実行に対応していない。キャラクタ・ディスプレイ・コントローラ AXI Slave IPの簡易的な単体テストとしては十分に使えると思う。

AXI Master BFMの Write の task がAXI_Master_1Seq_Write だ。このtaskは、(Write Address, Write Data), Write Response をシーケンシャルにオーバーラップせずに行う。今回の修正で、(Write Address, Write Data)はfork ~ join を使用して、オーバーラップするように変更した。AXI_Master_1Seq_Writeは、8個の引数を持つ。wait_clk_bready、wmax_wait 以外の信号はAXIバスの信号なので、説明は省く。wait_clk_bready はWriteのデータ転送が終了して、BREADYをアサートするまでのWaitクロック数を設定する。Writeデータ転送時にランダムな数のWaitが入るが、wmax_wait は、そのWait の最大値を指示する。

AXI Master BFMの Read の task が、AXI_Master_1Seq_Read で、Read Address, Read Data をシーケンシャルに行う。

下に、AXI Master BFM を示す。(2013/12/14:AWCACHE、ARCACHEを 3 に変更しました、input に DELAYを入れるように変更しました。)

// AXI4 bus Master Bus Fucntion Mode
// 2012/10/24 : 修正、S_AXI_AWREADYが1になるのを確認してからS_AXI_WVALIDを1にしていたのでは、AXIバスの非標準となる。
// よって、AXI_MASTER_WAC とAXI_MASTER_WDC をfork ~ join で並列に実行する
// 2013/12/14 : input に DELAYを入れるように変更
//

`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 = 3,    // Normal Non-cacheable 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 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;

    reg     S_AXI_AWREADY_d;
    reg     S_AXI_WREADY_d;
    reg     [0:0] S_AXI_BID_d;
    reg     [1:0] S_AXI_BRESP_d;
    reg     [0:0] S_AXI_BUSER_d;
    reg     S_AXI_BVALID_d;
    reg     S_AXI_ARREADY_d;
    reg     [0:0] S_AXI_RID_d;
    reg     [31:0] S_AXI_RDATA_d;
    reg     [1:0] S_AXI_RRESP_d;
    reg     S_AXI_RLAST_d;
    reg     [0:0] S_AXI_RUSER_d;
    reg     S_AXI_RVALID_d;

    always @* S_AXI_AWREADY_d <= #DELAY S_AXI_AWREADY;
    always @* S_AXI_WREADY_d <= #DELAY S_AXI_WREADY;
    always @* S_AXI_BID_d <= #DELAY S_AXI_BID;
    always @* S_AXI_BRESP_d <= #DELAY S_AXI_BRESP;
    always @* S_AXI_BUSER_d <= #DELAY S_AXI_BUSER;
    always @* S_AXI_BVALID_d <= #DELAY S_AXI_BVALID;
    always @* S_AXI_ARREADY_d <= #DELAY S_AXI_ARREADY;
    always @* S_AXI_RID_d <= #DELAY S_AXI_RID;
    always @* S_AXI_RDATA_d <= #DELAY S_AXI_RDATA;
    always @* S_AXI_RRESP_d <= #DELAY S_AXI_RRESP;
    always @* S_AXI_RLAST_d <= #DELAY S_AXI_RLAST;
    always @* S_AXI_RUSER_d <= #DELAY S_AXI_RUSER;
    always @* S_AXI_RVALID_d <= #DELAY S_AXI_RVALID;

    // Write Channel
    // wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
    // wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
    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
            fork
                AXI_MASTER_WAC(awid, awaddr, awlen, awsize, awburst);
                AXI_MASTER_WDC(wdata, wmax_wait);
            join
            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 トランザクションが開始されている場合は戻る
                axi_w_transaction_active = 1'b1; // AXIトランザクション開始

                awlen_hold        = awlen; // Write Data Channel のためにバースト数を取っておく
                @(posedge ACLK);    // 次のクロックへ

                while (~S_AXI_AWREADY_d) 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;
            end
        end
    endtask

    // Write Data Channel
    // wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
    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 (~S_AXI_AWVALID) begin    // S_AXI_AWVALID が1になるまで待つ
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end

            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) begin // waitなし
                    S_AXI_WVALID = 1'b1;
                end else begin // waitあり
                    S_AXI_WVALID = 1'b0;
                    for (j=0; j<val; 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_d) 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
    // wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
    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_d) begin // S_AXI_BVALID が1になるまでWait
                #DELAY;
                @(posedge ACLK);    // 次のクロックへ
            end
            #DELAY;

            S_AXI_BREADY = 1'b0;

            axi_w_transaction_active = 1'b0; // AXIトランザクション終了
            @(posedge ACLK);
            #DELAY;
        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_d) 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_d & S_AXI_RVALID_d & 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_d) 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トランザクション終了
            @(posedge ACLK);
            #DELAY;
        end
    endtask

endmodule

`default_nettype wire


  1. 2012年10月25日 05:50 |
  2. AX4 Lite Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.2(テストベンチのVerilogコード)

前の記事は、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.1(BFMシミュレーション7)”だが、全体の関連は、”AXI4 Slave IPの作製”を参照のこと。

今回はテストベンチのVerilogコードを下に貼っておく。(2013/12/14:修正、DELAYをAXI4 Master BFMへ移動しました)

// CDC_axi_slave_tb.v

`default_nettype none

`timescale 100ps / 1ps

module CDC_axi_slave_tb;

    parameter DELAY    = 10;
    parameter NUMBER_OF_TEST = 100;    // テストする数

    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
    wire S_AXI_AWREADY;
    wire S_AXI_WREADY;
    wire [0:0] S_AXI_BID;
    wire [1:0] S_AXI_BRESP;
    wire [0:0] S_AXI_BUSER;
    wire S_AXI_BVALID;
    wire S_AXI_ARREADY;
    wire [0:0] S_AXI_RID;
    wire [31:0] S_AXI_RDATA;
    wire [1:0] S_AXI_RRESP;
    wire S_AXI_RLAST;
    wire [0:0] S_AXI_RUSER;
    wire 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;

    // 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),
        .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),
        .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)
    );

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

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


    // test

    // Write Channel

    // wr_data生成、+1する
    reg        [15:0]    wcount;
    wire    [31:0]    wdata;

    always @(posedge ACLK) begin
        if (~ARESETN)
            wcount <= 0;
        else begin
            if (S_AXI_WVALID & S_AXI_WREADY)
                wcount <= wcount + 16'd1;
        end
    end
    assign wdata = {{16{1'b0}}, wcount};


    reg    WriteTaskBusy = 1'b0;
    integer wt_cnt;
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked

        @(posedge ACLK);    // 次のクロックへ
        #DELAY;

        for (wt_cnt=0; wt_cnt<NUMBER_OF_TEST; wt_cnt=wt_cnt+1) begin
            WriteTaskBusy = 1'b1;
            MBFMi.AXI_Master_1Seq_Write(0, 32'h100, 8'd7, ASIZE_BT_4, ABURST_INCR, wdata, 0, 2);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h200, 8'd3, ASIZE_BT_4, ABURST_INCR, wdata, 1, 3);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h300, 8'd1, ASIZE_BT_4, ABURST_INCR, wdata, 1, 4);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR, wdata, 1, 5);

            WriteTaskBusy = 1'b0;
            while (ReadTestBusy) begin // Read 終了待ち
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end
    end

    // Read Channel
    reg    ReadTestBusy = 1'b0;
    integer rd_cnt;
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked

        for (rd_cnt=0; rd_cnt<NUMBER_OF_TEST; rd_cnt=rd_cnt+1) begin

            ReadTestBusy = 1'b1;
            #1000;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            MBFMi.AXI_Master_1Seq_Read(0, 32'h100, 8'd7, ASIZE_BT_4, ABURST_INCR, 2);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h200, 8'd3, ASIZE_BT_4, ABURST_INCR, 3);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h300, 8'd1, ASIZE_BT_4, ABURST_INCR, 4);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR, 5);

            ReadTestBusy = 1'b0;
            while (WriteTaskBusy) begin // Write の終了待ち
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end
    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

  1. 2012年10月25日 05:33 |
  2. AXI4 Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

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

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

書き込みトランザクションの時に、MasterがAWREADYを待って、WVALIDをアサートしていけないというルールがあったのを忘れていたので、AXI Slave IP用のBFMが間違っていたことがわかったので修正する。ちなみにWriteだけ変更している。Readは変更していない。

”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする”シリーズの”BFMシミュレーション”~”BFMシミュレーション6”まで間違っているが、全部修正するのが大変なので、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8(BFMシミュレーション6)”のみ状態でのみ書きなおす。

テストベンチ (CDC_axi_slave_tb.v) を変更した。任意の回数ループするトランザクションは、8バースト、4バースト、2バースト、単発転送とする。それぞれデータ転送の最大のWait数を変えることにした。Readの値をovl_increment でチェックするため、Write トランザクションとRead トランザクションは、最後のトランザクションで同期する。Write トランザクションよりRead トランザクションの方が、遅延して開始する。

Writeの一部分を下に示す。
AXI_Slave_BFM_1_121025.png

Readの一部を下に示す。
AXI_Slave_BFM_2_121025.png

Writeの1トランザクションの拡大を下に示す。
AXI_Slave_BFM_3_121025.png

Readの1トランザクションの拡大を下に示す。
AXI_Slave_BFM_4_121025.png

テストベンチAXI Master BFMOVLチェッカはそれぞれ1つずつブログ記事を作って紹介する。
  1. 2012年10月25日 05:28 |
  2. AXI4 Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0