【SystemVerilog】UVMで検証環境を作成する~Sequence_item/Sequencer/Driver/Sequenceを追加する~【#4】

Systemverilog

前回のおさらい

テストベンチにAgent階層を追加しました。

sample_agent.svh
class sample_agent extends uvm_agent;
    `uvm_component_utils(sample_agent)

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

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Agent", UVM_NONE)
    endtask
endclass
sample_env.svh
class sample_env extends uvm_env;
    `uvm_component_utils(sample_env)

    sample_agent agent; // 追加

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

    function void build_phase(uvm_phase phase); // 追加
        super.build_phase(phase);
        agent = sample_agent::type_id::create("agent", this);
    endfunction

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Env", UVM_NONE);
    endtask
endclass

Sequence_item/Sequencer/Driver/Sequenceを追加する

uvm_sequence_itemtを継承したsample_sequence_item、
uvm_sequenceを継承したsample_seq、
uvm_sequencerを継承したsample_sequencer、
uvm_driverを継承したsample_driver
を作成します。

sample_sequence_item.svh

Sequencer/Driverでやり取りするデータをuvm_sequence_itemを継承して作成します。

class sample_sequence_item extends uvm_sequence_item;
    `uvm_object_utils(sample_sequence_item)

    rand bit [2:0] din1;
    rand bit [2:0] din2;

    function new(string name="sample_sequence_item");
        super.new(name);
    endfunction
endclass
sample_seq.svh

SequenceはSequencerを通してDriverを動作させます。

先ほど作成したsample_sequence_itemをパラメータにセットしたuvm_sequenceを継承してsample_seqを作成します。

class sample_seq extends uvm_sequence #(sample_sequence_item);
    `uvm_object_utils(sample_seq)

    rand bit [2:0] din1;
    rand bit [2:0] din2;

    function new(string name="sample_seq");
        super.new(name);
        set_automatic_phase_objection(1);  // おまじない
    endfunction

    virtual task body();
        `uvm_create(req)  // Sequencerを通してDriverを動作させる。
            req.din1 <= din1;
            req.din2 <= din2;
        `uvm_send(req)
        #10;
    endtask
endclass
sample_sequencer.svh

Sequencer階層はSequenceからの命令をDriverに伝えます。

先ほど作成したsample_sequence_itemをパラメータにセットしたuvm_sequencerを継承してsample_sequencerを作成します。

class sample_sequencer extends uvm_sequencer #(sample_sequence_item);
    `uvm_component_utils(sample_sequencer)

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

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Sequencer", UVM_NONE)
    endtask
endclass
sample_driver.svh

Driver階層はSequenceからの命令に従ってDUTを動作させます。

先ほど作成したsample_sequence_itemをパラメータにセットしたuvm_driverを継承してsample_driverを作成します。

class sample_driver extends uvm_driver #(sample_sequence_item);
    `uvm_component_utils(sample_driver)

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

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Driver", UVM_INFO)

        forever begin
            seq_item_port.get_next_item(req);

            `uvm_info(this.get_name(), $sformatf("din1 %d", req.din1), UVM_NONE)
            `uvm_info(this.get_name(), $sformatf("din2 %d", req.din2), UVM_NONE)

            seq_item_port.item_done(rsp);
        end
    endtask
endclass

Driver,Sequencer階層をAgent階層にインスタンスします。

sample_agent.svh(Sequencer/Driverをインスタンスする)

connect_phaseでsequencerとDriverを接続します。

class sample_agent extends uvm_agent;
    `uvm_component_utils(sample_agent)

    sample_driver driver;  // 追加。
    sample_sequencer sequencer;  // 追加。

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

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        driver = sample_driver::type_id::create("driver", this);  // 追加。
        sequencer = sample_sequencer::type_id::create("sequencer", this);  // 追加。
    endfunction

    function void connect_phase(uvm_phase phase);  // build_phaseの次に実行される。
        super.connect_phase(phase);
        driver.seq_item_port.connect(sequencer.seq_item_export);  // sequencerとdriverを接続する。
    endfunction

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Agent", UVM_NONE)
    endtask
endclass

Env階層に変更はありません。

sample_env.svh(変更なし)
class sample_env extends uvm_env;
    `uvm_component_utils(sample_env)

    sample_agent agent;

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

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        agent = sample_agent::type_id::create("agent", this);
    endfunction

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Env", UVM_NONE);
    endtask
endclass

Test階層にシーケンスを追加します。

sample_test.svh(Sequenceを追加する)
class sample_test extends uvm_test;
    `uvm_component_utils(sample_test)

    sample_env env;

    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, "env.agent.sequencer.run_phase",
            "default_sequence", sample_seq::type_id::get());
        env = sample_env::type_id::create("env", this);
    endfunction

    task run_phase(uvm_phase phase);
        `uvm_info(this.get_name(), "Hello World", UVM_NONE)
    endtask
endclass
top.sv(sample_sequence_item.svh, sample_sequencer.svh, sample_driver.svh, sample_seq.svhを追加する)
module top;
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    `include "sample_sequence_item.svh"  // 追加。
    `include "sample_sequencer.svh"  // 追加。
    `include "sample_driver.svh"  // 追加。
    `include "sample_agent.svh"
    `include "sample_env.svh"
    `include "sample_seq.svh"  // 追加。
    `include "sample_test.svh"

    initial begin
        run_test("sample_test");
    end
endmodule
実行結果

シミュレーションを実行すると以下が出力されます。

[UVM_INFO][uvm_test_top] Hello World
[UVM_INFO][env] Env
[UVM_INFO][agent] Agent
[UVM_INFO][sequencer] Sequencer
[UVM_INFO][driver] Driver
[UVM_INFO][driver] din1 4
[UVM_INFO][driver] din2 3

解説

sequence_itemは、sequenceからsequencerを通してdriverを動作させるときの変数を定義します。

Driverにある以下の記述をすると、sequence_itemの変数がreqの要素として使用できます。

seq_item_port.get_next_item(req);

以下の記述で、作成したsequencer, driverをagentで接続します。

function void connect_phase(uvm_phase phase);  // build_phaseの次に実行される。
    super.connect_phase(phase);
    driver.seq_item_port.connect(sequencer.seq_item_export);  // sequencerとdriverを接続する。
endfunction

以下の記述で、SequenceをTest階層に接続します。

uvm_config_db #(uvm_object_wrapper)::set( // シーケンスをセットする。
    this, "env.agent.sequencer.run_phase", "default_sequence", sample_seq::type_id::get());

まとめ

Sequence_item, Sequence, Sequencer, Driverを追加しました。

コメント

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