【UVM】クロック生成モデル

Systemverilog

はじめに

UVM環境でクロック生成モデルを作成します。

構成とサンプルコード

UVMモデルの構成

Sequence_item
class clock_sequence_item extends uvm_sequence_item;
    `uvm_object_utils(clock_sequence_item)

    rand bit en;

    function new(string name="clock_sequence_item");
        super.new(name);
    endfunction
endclass
Sequencer
class clock_sequencer extends uvm_sequencer #(clock_sequence_item);
    `uvm_component_utils(clock_sequencer)

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
endclass
Driver
class clock_driver extends uvm_driver #(clock_sequence_item);
    `uvm_component_utils(clock_driver)

    virtual clock_if vif;

    function new(string name, uvm_component parent);
        super.new(name, parent);
        if (!uvm_config_db #(virtual clock_if)::get(this, "clock", "vif", vif))
            `uvm_fatal(this.get_name(), "vif is invalid")
    endfunction

    task run_phase(uvm_phase phase);
        vif.en = 0;
        forever begin
            seq_item_port.get_next_item(req);
            vif.en = req.en;
            seq_item_port.item_done(rsp);
        end
    endtask
endclass
Agent
class clock_agent extends uvm_agent;
    `uvm_component_utils(clock_agent)

    clock_driver driver;
    clock_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 = clock_driver::type_id::create("driver", this);
        sequencer = clock_sequencer::type_id::create("sequencer", this);
    endfunction

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        driver.seq_item_port.connect(sequencer.seq_item_export);
    endfunction
endclass
Sequence
class clock_seq extends uvm_sequence #(clock_sequence_item);
    `uvm_object_utils(clock_seq)

    rand bit en;

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

    virtual task body();
        `uvm_create(req)
        req.en = en;
        `uvm_send(req)
    endtask
endclass
package
package clock_pkg;
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    `include "clock_sequence_item.svh"
    `include "clock_sequencer.svh"
    `include "clock_driver.svh"
    `include "clock_agent.svh"
    `include "clock_seq.svh"
endpackage
Interface

※クロック生成回路付き。

interface clock_if;
    logic en;
endinterface

module clock #(
    parameter HIGH = 1,
    parameter LOW = 1
)(
    output logic clk
);
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    clock_if vif();

    always begin
        clk = 0;
        @(vif.en === 1);
        fork
            begin
                @(vif.en === 0);
                clk = 0;
            end
            begin
                forever begin
                    #LOW;
                    clk = ~clk;
                    #HIGH;
                    clk = ~clk;
                end
            end
        join_any
        disable fork;
    end

    initial begin
        uvm_config_db #(virtual clock_if)::set(null, "*clock*", "vif", vif);
    end
endmodule

サンプル動作環境

Virtual Sequencer
class sample_vsequencer extends uvm_sequencer;
    `uvm_component_utils(sample_vsequencer)

    clock_sequencer seqr;

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

    clock_seq seq;

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

    virtual task body();
        seq = clock_seq::type_id::create("seq");
        for (int i = 0; i < 2; i++) begin
            `uvm_do_on_with(seq, p_sequencer.seqr, {
                en == 0;  // 0のときクロックは停止する。
            })
            #50;
            `uvm_do_on_with(seq, p_sequencer.seqr, {
                en == 1;  // 1のときクロックが動き出す。
            })
            #50;
        end
    endtask
endclass
Test
class sample_test extends uvm_test;
    `uvm_component_utils(sample_test)

    clock_agent agent;
    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());
        agent = clock_agent::type_id::create("agent", this);
        vsequencer = sample_vsequencer::type_id::create("vsequencer", this);
    endfunction

    function void connect_phase(uvm_phase phase);
        $cast(vsequencer.seqr, agent.sequencer);
    endfunction
endclass
テストベンチ
`include "clock_pkg.svh"
module top;
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    import clock_pkg::*;

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

    initial begin
        run_test("sample_test");
    end

    logic clk;
    clock #(
        .HIGH(2),
        .LOW(1)
    ) i_clock(clk);
endmodule

まとめ

UVM環境でクロック生成モデルを作成しました。

コメント

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