【UVM】Register階層を作成する~uvm_regでレジスタを管理する~【#1】

Systemverilog

はじめに

Register階層(Register Layer)を作成します。

UVMではレジスタをuvm_regを継承したクラスで定義します。

1レジスタごとに1クラスを作成して、uvm_reg_blockを継承したクラスで1まとめにします。

サンプルコード

sample_reg_block.svh

レジスタクラスSTATUS_regを作成してsample_reg_blockの要素にします。

class STATUS_reg extends uvm_reg; // レジスタクラス。
    `uvm_object_utils(STATUS_reg)

    function new(string name="STATUS_reg");
        super.new(name, 8, UVM_NO_COVERAGE);
    endfunction

    rand uvm_reg_field status;

    function void build();
        status = uvm_reg_field::type_id::create("status");
        status.configure(
            .parent(this),  // とりあえずthisでOK。
            .size(8),  // レジスタのビット幅
            .lsb_pos(0),  // LSBの開始位置
            .access("RW"),  // アクセスタイプ
            .volatile(0),  // わからん。
            .reset(0),  // 初期値
            .has_reset(1),  // リセット値を持つかどうか。
            .is_rand(1),  // 乱数対応
            .individually_accessible(0)  // わからん。
        );
    endfunction
endclass

class sample_reg_block extends uvm_reg_block;  // レジスタクラスをまとめる。
    rand STATUS_reg STATUS;  // 作成したレジスタクラスを羅列する。

    `uvm_object_utils(sample_reg_block)
    function new(string name="sample_reg_block");
        super.new(name, build_coverage(UVM_NO_COVERAGE));
    endfunction

    function void build();
        STATUS = STATUS_reg::type_id::create("STATUS");
        STATUS.configure(this);
        STATUS.build();

        default_map = create_map("", 0, 1, UVM_LITTLE_ENDIAN);
        default_map.add_reg(STATUS, 'h1); // レジスタクラスを追加する。
    endfunction
endclass
sample_env.svh

sample_reg_blockをぶら下げます。

class sample_env extends uvm_env;
    `uvm_component_utils(sample_env)
    sample_reg_block regmodel;

    function new(string name="sample_env", uvm_component parent);
        super.new(name, parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        regmodel = sample_reg_block::type_id::create("regmodel");
        regmodel.build();  // buildを実行する
        regmodel.lock_model(); // コンフィグをこれ以降変更できないようにする。

        uvm_config_db#(sample_reg_block)::set(uvm_root::get(), "*", "regmodel", regmodel);
    endfunction

    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        regmodel.default_map.set_base_addr('h0);  // 開始アドレスを設定する。
    endfunction
endclass
sample_vsequencer.svh

Virtual Sequenceで使用するようにregmodelを宣言します。

class sample_vsequencer extends uvm_sequencer;
    `uvm_component_utils(sample_vsequencer)

    sample_reg_block regmodel;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
endclass
sample_vseq.svh
class sample_vseq extends uvm_sequence;
    `uvm_object_utils(sample_vseq)
    `uvm_declare_p_sequencer(sample_vsequencer)

    function new(string name="sample_vseq");
        super.new(name);
        set_automatic_phase_objection(1);
    endfunction

    virtual task body();
        byte data;
        data = p_sequencer.regmodel.STATUS.get_address();  // アドレスを取得する。
        `uvm_info(this.get_name(), $sformatf("%h", data), UVM_NONE)
    endtask
endclass
その他のファイル
module top;
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    `include "sample_reg_block.svh"
    `include "sample_env.svh"
    `include "sample_vsequencer.svh"
    `include "sample_vseq.svh"
    `include "sample_test.svh"

    initial begin
        run_test("sample_test");
    end

    bit clk = 0;
    always #1 clk = ~clk;
    bit rst_n = 0;
    initial #10 rst_n = 1;

    logic write_en;
    logic [7:0] addr;
    logic [7:0] data;

    regbus i_regbus (
        .clk(clk),
        .rst_n(rst_n),
        .write_en(write_en),
        .addr(addr),
        .data(data)
    );
endmodule
interface regbus_if (
    logic clk,
    logic rst_n
);
    logic write_en;
    logic [7:0] addr;
    logic [7:0] data;
endinterface

module regbus #(
)(
    input clk,
    input rst_n,
    output logic write_en,
    output logic [7:0] addr,
    output logic [7:0] data
);
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    regbus_if vif(
        .clk(clk),
        .rst_n(rst_n)
    );

    assign data = vif.data;
    assign addr = vif.addr;
    assign write_en = vif.write_en;

    initial begin
        uvm_config_db #(virtual regbus_if)::set(null, "*regbus*", "vif", vif);
    end
endmodule
class sample_test extends uvm_test;
    `uvm_component_utils(sample_test)

    sample_env env;
    sample_vsequencer vsequencer;

    function new(string name="sample_test", uvm_component parent=null);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        uvm_config_db #(uvm_object_wrapper)::set(
            this, "vsequencer.run_phase",
            "default_sequence", sample_vseq::type_id::get());
        env = sample_env::type_id::create("env", this);
        vsequencer = sample_vsequencer::type_id::create("vsequencer", this);
    endfunction

    function void connect_phase(uvm_phase phase);
        $cast(vsequencer.regmodel, env.regmodel);
    endfunction
endclass
実行結果
[UVM_INFO][sample_vseq] 01

まとめ

Register階層を作成しました。

コメント

タイトルとURLをコピーしました