sequence library
随机选择sequence
所谓sequence library,就是一系列sequence的集合。sequence_library类的原型为:
class uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ)
extends uvm_sequence #(REQ,RSP);
sequence library派生自uvm_sequence,从本质上是sequence,根据特定算法随机选择注册在其中的一些sequence,并在body中执行这些sequence。
一个sequence library的定义如下:
class simple_seq_library extends uvm_sequence_library#(my_transaction);
function new(string name= "simple_seq_library");
super.new(name);
init_sequence_library();
endfunction
`uvm_object_utils(simple_seq_library)
`uvm_sequence_library_utils(simple_seq_library);
endclass
在定义sequence library时要特别注意:
- 一是从uvm_sequence派生时要指明此sequence library产生的transaction类型;
- 二是在其new函数中要调用init_sequence_library,否则其内部的候选sequence队列就是空的;
- 三是要调用uvm_sequence_library_utils注册。
sequence library在定义之后如果没有任何sequence注册到其中,是没有任何意义的。一个sequence在定义时使用宏`uvm_add_to_seq_lib来将其加入某个sequence library中:
class seq0 extends uvm_sequence#(my_transaction);
…
`uvm_object_utils(seq0)
`uvm_add_to_seq_lib(seq0, simple_seq_library)
virtual task body();
repeat(10) begin
`uvm_do(req)
`uvm_info("seq0", "this is seq0", UVM_MEDIUM)
end
endtask
endclass
uvm_add_to_seq_lib有两个参数:此sequence的名字和要加入的sequence library名字。一个sequence可以加入多个不同的sequence library中:
class seq0 extends uvm_sequence#(my_transaction);
`uvm_object_utils(seq0)
`uvm_add_to_seq_lib(seq0, simple_seq_library)
`uvm_add_to_seq_lib(seq0, hard_seq_library)
virtual task body();
repeat(10) begin
`uvm_do(req)
`uvm_info("seq0", "this is seq0", UVM_MEDIUM)
end
endtask
endclass
同样的,可以有多个sequence加入同一sequence library中:
class seq1 extends uvm_sequence#(my_transaction);
…
`uvm_object_utils(seq1)
`uvm_add_to_seq_lib(seq1, simple_seq_library)
virtual task body();
repeat(10) begin
`uvm_do(req)
`uvm_info("seq1", "this is seq1", UVM_MEDIUM)
end
endtask
endclass
当sequence与sequence library定义好后,可以将sequence library作为sequencer的default sequence:
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence", simple_seq_library::type_id::get());
endfunction
执行代码会发现UVM随机从加入simple_seq_library的sequence中选择几个并顺序启动它们。
控制选择算法
上节中sequence library随机从其sequence队列中选择几个执行。这是由其变量selection_mode决定的,这个变量的定义为:uvm_sequence_lib_mode selection_mode;
uvm_sequence_lib_mode是一个枚举类型,共有四个值:
typedef enum
{
UVM_SEQ_LIB_RAND,
UVM_SEQ_LIB_RANDC,
UVM_SEQ_LIB_ITEM,
UVM_SEQ_LIB_USER
} uvm_sequence_lib_mode;
- UVM_SEQ_LIB_RAND就是完全的随机,上节例子就是这种算法;
- UVM_SEQ_LIB_RANDC就是将加入的sequence随机排一个顺序,然后按照此顺序执行。这可以保证每个sequence执行一遍,在所有sequence被执行完一遍之前,不会有sequence被执行第二次,其配置方式如下:
function void my_case0::build_phase(uvm_phase phase);
…
uvm_config_db#(uvm_sequence_lib_mode)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence.selection_mode", UVM_SEQ_LIB_RANDC);
endfunction
- UVM_SEQ_LIB_ITEM是sequence library并不执行其sequence队列中的sequence,而是自己产生transaction。sequence library在此种情况下就是普通的sequence,只是其产生的transaction除了定义时施加的约束外,没有任何额外的约束。
- UVM_SEQ_LIB_USER是用户自定义选择的算法。需用户重载select_sequence参数:
class simple_seq_library extends uvm_sequence_library#(my_transaction);
function new(string name= "simple_seq_library");
super.new(name);
init_sequence_library();
endfunction
`uvm_object_utils(simple_seq_library)
`uvm_sequence_library_utils(simple_seq_library);
virtual function int unsigned select_sequence(int unsigned max);
static int unsigned index[$];
static bit inited;
int value;
if(!inited) begin
for(int i = 0; i <= max; i++) begin
if((sequences[i].get_type_name() == "seq0") ||
(sequences[i].get_type_name() == "seq1") ||
(sequences[i].get_type_name() == "seq3"))
index.push_back(i);
end
inited = 1;
end
value = $urandom_range(0, index.size() - 1);
return index[value];
endfunction
endclass
- 假设有4个sequence加入了sequence library中:seq0、seq1、seq2和seq3。
- 由于各种原因不想使用seq2。上述代码的select_sequence第一次被调用时初始化index队列,把seq0、seq1和seq3在sequences中的索引号存入其中。
- 之后从index中随机选择一个值返回,相当于是从seq0、seq1和seq3随机选一个执行。
- sequences是sequence library中存放候选sequence的队列。select_sequence传入参数max,select_sequence函数必须返回一个介于0到max之间的数值。如果sequences队列的大小为4,那么传入的max的数值是3,而不是4。
控制执行次数
上面代码执行的次数都是10次,这是由sequence library内部的两个变量控制的:
int unsigned min_random_count=10;
int unsigned max_random_count=10;
sequence library会在min_random_count和max_random_count之间随意选择一个数来作为执行次数。当selection_mode为UVM_SEQ_LIB_ITEM时,会产生10个item;其他模式时,将会顺序启动10个sequence。可设置这两个值为其他值来改变迭代次数:
function void my_case0::build_phase(uvm_phase phase);
…
uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence", simple_seq_library::type_id::get());
uvm_config_db#(uvm_sequence_lib_mode)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence.selection_mode", UVM_SEQ_LIB_ITEM);
uvm_config_db#(int unsigned)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence.min_random_count", 5);
uvm_config_db#(int unsigned)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence.max_random_count", 20);
endfunction
上述设置将会产生最多20个,最少5个transaction
使用sequence_library_cfg
使用3个config_db设置迭代次数和选择算法稍显麻烦。UVM提供uvm_sequence_library_cfg对sequence library进行配置。它一共有三个成员变量:
class uvm_sequence_library_cfg extends uvm_object;
`uvm_object_utils(uvm_sequence_library_cfg)
uvm_sequence_lib_mode selection_mode;
int unsigned min_random_count;
int unsigned max_random_count;
…
endclass
通过配置如上三个成员变量,并将其传递给sequence library就可对sequence library进行配置:
function void my_case0::build_phase(uvm_phase phase);
uvm_sequence_library_cfg cfg;
super.build_phase(phase);
cfg = new("cfg", UVM_SEQ_LIB_RANDC, 5, 20); //notice
uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence", simple_seq_library::type_id::get());
uvm_config_db#(uvm_sequence_library_cfg)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence.config", cfg);
endfunction
除使用专门的cfg外,还有一种简单的配置方法是启动sequence时,在对sequence library进行实例化后,对其中的变量进行赋值:
function void my_case0::build_phase(uvm_phase phase);
simple_seq_library seq_lib;
super.build_phase(phase);
seq_lib = new("seq_lib");
seq_lib.selection_mode = UVM_SEQ_LIB_RANDC;
seq_lib.min_random_count = 10;
seq_lib.max_random_count = 15;
uvm_config_db#(uvm_sequence_base)::set(this, "env.i_agt.sqr.main_phase",
"default_sequence", seq_lib);
endfunction