Help us understand the problem. What is going on with this article?

uvm_sequence_libraryの使い方

More than 1 year has passed since last update.

uvm_sequence_libaryはuvm_sequenceのサブクラスとなっており、基本的な使い方は同じです。さらに、uvm_sequence_libraryにuvm_sequenceを登録しておくと、それを複数回ランダムな順番に実行してくれます。

手順の概要は以下の通りになります。
1. uvm_sequence_libraryにuvm_sequenceを登録する。これには3種類の方法があります
2. min_random_count, max_roundom_count等のプロパティーにランダマイズ用のパラメターを設定する
3. randomize()を呼ぶ
4. (uvm_sequenceと同様に)start()でシーケンスライブラリをスタートさせる

例えば以下の例ではseq_a, seq_bを登録して、それぞれの最小実行回数を10に設定してシーケンスライブラリをスタートさせています。結果としてseq_aとseq_bがランダムな順番で最低10回ずつ実行されます。

seq_lib.add_sequence(seq_a::get_type());
seq_lib.add_sequence(seq_b::get_type());
seq_lib.min_random_count = 10;
seq_lib.randomize();
seq_lib.start();

uvm_sequenceの登録方法

3通りの方法があります。

uvm_sequence_library.add_sequence()を使用する

引数はuvm_sequenceのtypeになります。

uvm_sequence_library_h = uvm_sequence_library#(uvm_sequence_item)::type_id::create("uvm_sequence_library");
uvm_sequence_library_h.add_sequence(uvm_sequence::get_type());

uvm_sequence_library::add_typewide_sequence()を使用する

こちらはクラスメソッドになります。引数はtypeです。
クラスメソッドなので、対象のクラス全てにuvm_sequenceが登録されます。登録した後にcreate()して使います。

uvm_sequence_library::add_typewide_sequence(uvm_sequence::get_type());
uvm_sequence_library_h = uvm_sequence_library::type_id::create("my_sequence_library");

uvm_add_to_seq_libマクロを使用する

このマクロは登録したいシーケンスの中で使います。
第一引数が自分自身のクラス名、第二引数が登録したいシーケンスライブラリのクラス名です。

class my_sequence extends uvm_sequence #(my_sequence_item);
  `uvm_object_utils(my_sequence)
  `uvm_add_to_seq_lib(my_sequence, my_sequence_library)
  function new(string name = "my_sequence");
    super.new(name);
  endfunction
  ...
endclass

サンプルプログラム

サンプルプログラムです。上記それぞれ3つの方法でシーケンスライブラリを作り、実行します。全てmin_random_countとmax_random_countを2に設定していますので、シーケンス実行回数は2回に固定されます。
以下がサンプルプログラム全文です。EDA Playgroundでは以下から実行できます。
https://www.edaplayground.com/x/5EZC

import uvm_pkg::*;
`include "uvm_macros.svh"

class my_sequence_item extends uvm_sequence_item;
  string str;
  `uvm_object_utils(my_sequence_item)

  function new(string name = "my_sequence_item");
    super.new(name);
  endfunction
endclass


typedef class my_sequence_library_b;


class my_sequence extends uvm_sequence #(my_sequence_item);
  `uvm_object_utils(my_sequence)

  `uvm_add_to_seq_lib(my_sequence, my_sequence_library_b)

  function new(string name = "my_sequence");
    super.new(name);
  endfunction

  virtual task body();
    req = my_sequence_item::type_id::create("req");

    start_item(req);
    req.str = get_full_name();
    finish_item(req);
  endtask
endclass


class my_sequence_library_a extends uvm_sequence_library #(my_sequence_item);
  `uvm_object_utils(my_sequence_library_a)
  `uvm_sequence_library_utils(my_sequence_library_a)

  function new(string name = "my_sequence_library_a");
    super.new(name);
    init_sequence_library();
  endfunction
endclass


class my_sequence_library_b extends uvm_sequence_library #(my_sequence_item);
  `uvm_object_utils(my_sequence_library_b)
  `uvm_sequence_library_utils(my_sequence_library_b)

  function new(string name = "my_sequence_library_b");
    super.new(name);
    init_sequence_library();
  endfunction
endclass


class my_driver extends uvm_driver #(my_sequence_item);
  `uvm_component_utils(my_driver)

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

  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    forever begin
      seq_item_port.get_next_item(req);
      #10ns;
      `uvm_info(get_type_name(), $sformatf("Passed string = %s", req.str), UVM_NONE);
      seq_item_port.item_done();
    end
  endtask
endclass


class my_agent extends uvm_component;
  my_driver my_driver_h;
  uvm_sequencer #(my_sequence_item) my_sequencer_h;

  `uvm_component_utils(my_agent)

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

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    my_sequencer_h = uvm_sequencer#(my_sequence_item)::type_id::create("my_sequencer", this);
    my_driver_h = my_driver::type_id::create("my_driver", this);
  endfunction

  virtual function void connect_phase(uvm_phase phase);
    my_driver_h.seq_item_port.connect(my_sequencer_h.seq_item_export);
  endfunction
endclass


class my_env extends uvm_env;
  my_agent my_agent_h;

  `uvm_component_utils(my_env)

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

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    my_agent_h = my_agent::type_id::create("my_agent", this);
  endfunction
endclass


class my_test extends uvm_test;
  `uvm_component_utils(my_test)

  my_env my_env_h;

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

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    my_env_h = my_env::type_id::create("my_env", this);
  endfunction

  virtual task run_phase(uvm_phase phase);
    uvm_root uvm_root_h = uvm_root::get();
    uvm_sequencer #(my_sequence_item) my_sequencer_h;

    uvm_sequence_library#(my_sequence_item) uvm_sequence_library_h;
    my_sequence_library_a my_sequence_library_a_h;
    my_sequence_library_b my_sequence_library_b_h;

    // Option 1. Use add_sequence method
    uvm_sequence_library_h = uvm_sequence_library#(my_sequence_item)::type_id::create("uvm_sequence_library");
    uvm_sequence_library_h.add_sequence(my_sequence::get_type());
    uvm_sequence_library_h.min_random_count = 2;
    uvm_sequence_library_h.max_random_count = 2;
    if (!uvm_sequence_library_h.randomize()) begin
      `uvm_error(get_type_name(), "randomization error")
    end

    // Option 2. Use add_typewide_sequence class method
    my_sequence_library_a::add_typewide_sequence(my_sequence::get_type());
    my_sequence_library_a_h = my_sequence_library_a::type_id::create("my_sequence_library_a");
    my_sequence_library_a_h.min_random_count = 2;
    my_sequence_library_a_h.max_random_count = 2;
    if (!my_sequence_library_a_h.randomize()) begin
      `uvm_error(get_type_name(), "randomization error")
    end

    // Option 3. Use uvm_add_to_seq_lib macro
    my_sequence_library_b_h = my_sequence_library_b::type_id::create("my_sequence_library_b");
    my_sequence_library_b_h.min_random_count = 2;
    my_sequence_library_b_h.max_random_count = 2;
    if (!my_sequence_library_b_h.randomize()) begin
      `uvm_error(get_type_name(), "randomization error")
    end

    // Obtain handle to uvm_sequencer
    $cast(my_sequencer_h, uvm_root_h.find("uvm_test_top.my_env.my_agent.my_sequencer"));
    if (my_sequencer_h == null) begin
      `uvm_error(get_type_name(), "The sequencer was not found")
    end

    // Start sequences
    phase.raise_objection(this);
    uvm_sequence_library_h.start(my_sequencer_h);
    my_sequence_library_a_h.start(my_sequencer_h);
    my_sequence_library_b_h.start(my_sequencer_h);
    phase.drop_objection(this);
  endtask
endclass

module top();
  initial begin
    run_test("my_test");
  end
endmodule

解説

uvm_sequenceは自分のfull_nameをuvm_sequene_itemに登録して、uvm_driverに送ります。

    start_item(req);
    req.str = get_full_name();
    finish_item(req);

uvm_driverはuvm_sequenceからuvm_sequence_itemを受け取ると、以下でその内容を表示します。

    forever begin
      seq_item_port.get_next_item(req);
      #10ns;
      `uvm_info(get_type_name(), $sformatf("Passed string = %s", req.str), UVM_NONE);
      seq_item_port.item_done();
    end

実行結果

実行結果です。

# KERNEL: UVM_INFO @ 0: reporter [RNTST] Running test my_test...
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(663) @ 0: uvm_test_top.my_env.my_agent.my_sequencer@@uvm_sequence_library [SEQLIB/START] Starting sequence library uvm_sequence_library #(REQ,RSP) in unknown phase: 2 iterations in mode UVM_SEQ_LIB_RAND
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 10: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.uvm_sequence_library.my_sequence:1
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 20: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.uvm_sequence_library.my_sequence:2
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(737) @ 20: uvm_test_top.my_env.my_agent.my_sequencer@@uvm_sequence_library [SEQLIB/END] Ending sequence library in phase unknown
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(663) @ 20: uvm_test_top.my_env.my_agent.my_sequencer@@my_sequence_library_a [SEQLIB/START] Starting sequence library my_sequence_library_a in unknown phase: 2 iterations in mode UVM_SEQ_LIB_RAND
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 30: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.my_sequence_library_a.my_sequence:1
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 40: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.my_sequence_library_a.my_sequence:2
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(737) @ 40: uvm_test_top.my_env.my_agent.my_sequencer@@my_sequence_library_a [SEQLIB/END] Ending sequence library in phase unknown
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(663) @ 40: uvm_test_top.my_env.my_agent.my_sequencer@@my_sequence_library_b [SEQLIB/START] Starting sequence library my_sequence_library_b in unknown phase: 2 iterations in mode UVM_SEQ_LIB_RAND
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 50: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.my_sequence_library_b.my_sequence:1
# KERNEL: UVM_INFO /home/runner/testbench.sv(70) @ 60: uvm_test_top.my_env.my_agent.my_driver [my_driver] Passed string = uvm_test_top.my_env.my_agent.my_sequencer.my_sequence_library_b.my_sequence:2
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/seq/uvm_sequence_library.svh(737) @ 60: uvm_test_top.my_env.my_agent.my_sequencer@@my_sequence_library_b [SEQLIB/END] Ending sequence library in phase unknown
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 60: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/base/uvm_report_server.svh(856) @ 60: reporter [UVM/REPORT/SERVER] 

uvm_sequence_libraryにはここで説明した以外にも実行するuvm_sequenceをランダムに選ぶ方法のアルゴリズムを指定するプロパティー等があります。詳細は以下のリファレンスマニュアルを参照してください。

参考文献

Accellera, "20.4 uvm_sequence_library", Universal Verification Methodology (UVM) 1.2 Class Reference, pp.431-435.

triggerfish
ASIC職人です。デザイナですが検証もやります。ネタとしては検証のほうが書きやすいので、そちらが記事のメインになると思います。入門記事よりはプロの方が実務で役に立つような記事を目指しています。内容に不明点がありましたら遠慮なく質問をお願いいたします!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした