uvm_sequence_libaryはuvm_sequenceのサブクラスとなっており、基本的な使い方は同じです。さらに、uvm_sequence_libraryにuvm_sequenceを登録しておくと、それを複数回ランダムな順番に実行してくれます。
手順の概要は以下の通りになります。
- uvm_sequence_libraryにuvm_sequenceを登録する。これには3種類の方法があります
- min_random_count, max_roundom_count等のプロパティーにランダマイズ用のパラメターを設定する
- randomize()を呼ぶ
- (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]
(https://www.accellera.org/images/downloads/standards/uvm/UVM_Class_Reference_Manual_1.2.pdf), pp.431-435.