UVM基础-sequence library

1.1 sequence library在环境中的使用

       uvm_sequence_library定义为是一堆sequence的集合,本质上其实就是uvm_sequence,只不过在普通的uvm_sequence的基础上封装了多种算法,支持对内部sequence的随机发送,或者有序发送等,在随机测试场景下会发挥大作用,从源码上看,uvm_sequnce_library实际上就是继承自uvm_sequence:

 在uvm_sequence_library中会维护一个sequence的队列,每加入一个sequence,就会在队列中加入一个sequence。用户自定义的sequence_library可以继承自uvm_sequence_library:

1.	class my_seq_library0 extends uvm_sequence_library#(uvm_sequence_item);
2.	      `uvm_object_utils(my_seq_library0)
3.	      `uvm_sequence_library_utils(my_seq_library0)
4.	      function void new(string name="my_seq_library0");
5.	           super.new(name);
6.	           init_sequence_library();
7.	      endfunction:new
8.	endclass

在声明sequence_library的时候,需要注意三个点:

  • seq_library要继承自uvm_sequence_library,且需要指定参数,一般为uvm_sequence_item,也可以是用户自定的transaction类型。
  • seq_library除了要注册到uvm_object_utils之外,还需要通过`uvm_sequence_library_utils宏进行注册;
  • 在seq_library的new函数中,需要调用init_sequence_library()函数初始化library中的sequence队列。

声明完一个sequence_library,如果不加入任何的sequence,那么这个sequence_library为空,这样的library不具备任何作用,需要在自定义的sequence中,将自定sequence加入到这个sequence_library中:

1.	class my_sequence extends uvm_sequence#(uvm_sequence_item);
2.	      my_transaction my_tr;
3.	      `uvm_object_utils(my_sequence)
4.	      `uvm_add_to_seq_lib(my_sequence, my_seq_library0)
5.	......
6.	      virtual task body();
7.	            repeat(10) begin
8.	                `uvm_do(my_tr)
9.	            end
10.	      endtask:body
11.	......
12.	endclass

在自定义的sequence中,使用uvm_add_to_seq_lib加入到sequence_library中,这个宏有两个参数,第一个是需要加入的sequence,第二个是sequence_library的名字。

       同样的,对于同一个sequence,可以加入到不同的sequence_library中,上述代码可以写为:

1.	class my_sequence extends uvm_sequence#(uvm_sequence_item);
2.	      my_transaction my_tr;
3.	      `uvm_object_utils(my_sequence)
4.	      `uvm_add_to_seq_lib(my_sequence, my_seq_library0)
5.	      `uvm_add_to_seq_lib(my_sequence, my_seq_library1)
6.	      `uvm_add_to_seq_lib(my_sequence, my_seq_library2)
7.	......
8.	      virtual task body();
9.	            repeat(10) begin
10.	                `uvm_do(my_tr)
11.	            end
12.	      endtask:body
13.	......
14.	endclass

另外,对于同一个sequence_library,也可以加入不同的sequence,比如有另外一个my_sequence_new:

1.	class my_sequence_new extends uvm_sequence#(uvm_sequence_item);
2.	      my_transaction my_tr;
3.	      `uvm_object_utils(my_sequence_new)
4.	      `uvm_add_to_seq_lib(my_sequence_new, my_seq_library0)
5.	......
6.	      virtual task body();
7.	            repeat(10) begin
8.	                `uvm_do(my_tr)
9.	            end
10.	      endtask:body
11.	......
12.	endclass

1.2 sequence library的启动方法

       sequence_library的启动实际上和sequence的启动类似,可以作为sequencer中main_phase的default_sequence启动,也可以调用sequence_library的start函数进行启动。

在tc中:

1.	class my_tc extends base_test;
2.	      my_seq_library0  seq_lib;
3.	      `uvm_component_utils(my_tc)
4.	......
5.	      virtual function void build_phase(uvm_phase phase);
6.	           super.build_phase(phase);
7.	           seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	           uvm_config_db#(uvm_sequence_base)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", seq_lib);
9.	       endfunction:build_phase
10.	......
11.	endclass

或者也可以写成:

1.	class my_tc extends base_test;
2.	      my_seq_library0  seq_lib;
3.	      `uvm_component_utils(my_tc)
4.	......
5.	      virtual function void build_phase(uvm_phase phase);
6.	           super.build_phase(phase);
7.	           //seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	           uvm_config_db#(uvm_object_wrap)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", seq_lib::type_id::get());
9.	       endfunction:build_phase
10.	......
11.	endclass

这里注意的是使用type_id::get()方法返回的是uvm_object_wrap类型的变量,和factory机制有关,因此uvm_config_db的参数必须是uvm_object_wrap,而使用seq_lib直接作为default_seq启动,则uvm_config_db的参数应该传递为uvm_sequence_base类型。

       另外,还可以通过调用seq_lib的start函数启动,在tc的main_phase中:

1.	class my_tc extends base_test;
2.	      my_seq_library0  seq_lib;
3.	      `uvm_component_utils(my_tc)
4.	......
5.	      virtual function void build_phase(uvm_phase phase);
6.	           super.build_phase(phase);
7.	           seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	           //uvm_config_db#(uvm_object_wrap)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", seq_lib::type_id::get());
9.	       endfunction:build_phase
10.	
11.	       virtual function void main_phase(uvm_phase phase);
12.	           super.main_phase(phase);
13.	           phase.raise_objection(this);
14.	           seq_lib.start(env.i_agt.sqr, null, -1);
15.	           phase.drop_objection(this);
16.	       endfunction:main_phase
17.	......
18.	endclass

本质上,sequence_library和普通的sequence没有差别,所以启动方式也和普通的sequence方法一样。从uvm_sequence_library的源码也可以看出来,其继承自uvm_sequence,可以理解为在常规的sequence基础上封装了一层,然后内部丰富了sequence的发送算法和随机数量。

2.1 选择算法控制

如果不加任何设置,调用start任务后,sequence_library将会随机发送加入到library的sequence,uvm提供了4种sequence_library的模式,在基类uvm_sequence_library中,通过select_mode控制:

       select_mode的默认模式是:UVM_SEQ_LIB_RAND,也就是完全随机,那么其他几种模式的含义:

UVM_SEQ_LIB_RAND

完全随机发送sequence

UVM_SEQ_LIB_RANDC

将加入到sequence_library中的数据随机排一个顺序,然后进行依次发送,能保证内部每个sequence都被发送一次

UVM_SEQ_LIB_ITEM

不发送加入到sequence library中的sequence,发送自己产生的sequence,此时sequence library相当于一个普通的sequence

UVM_SEQ_LIB_USER

采用用户自定义的方式发送sequence,需要重载select_sequence方法实现

       这里重点说明下UVM_SEQ_LIB_USER的用法,如果用户将sequence_library的模式设定为该模式,需要重载select_sequence方法,这个方法的原型为:

重载该函数,实现用户自定义的sequence的发送,在sequence_library中:

1.	class my_seq_lib extends uvm_sequence_library#(uvm_sequence_item);
2.	      `uvm_object_utils(my_seq_lib)
3.	      `uvm_sequence_library_utils(my_seq_lib)
4.	      function void new(string name="my_seq_lib");
5.	          super.new(name);
6.	          init_sequence_library();
7.	      endfunction:new
8.	      virtual function int unsigned select_sequence(int unsigned max);
9.	          static int unsigned index[$];
10.	          static bit inited;
11.	          int value;
12.	          if (!inited) begin
13.	               for(int i=0; i<=max; i++) begin
14.	                      if((sequence[i].get_type_name() == "seq0") || 
15.	                         (sequence[i].get_type_name() == "seq1") ||
16.	                         (sequence[i].get_type_name() == "seq3") ) begin
17.	                         index.push_back(i);
18.	               end
19.	               inited = 1'b1;
20.	           end
21.	           value = $urandom_range(0, index.size()-1);
22.	           return index[value];
23.	       endfunction:select_sequence
24.	endclass

重载函数的含义是:初始化一开始inited为0,如果在sequence_library内部的sequence队列中加入seq0、seq1和seq3,那么会将index队列增加seq的序号,然后将初始化inited赋值为1,也就是只进行一次index的入队,循环外使用一个随机选取index队列中的序号,将序号返回,返回后,sequence_library会按照返回值发送sequence。也就是说这个功能为:只在sequence序号为0,1,3的sequence中随机选取一个发送。

这里用到了sequence_library中维护的sequence队列sequence[$],其源码为:

即注册到factory机制的加入sequence_library中的所有sequence。

 

2.2 运行次数控制

       实际上,在sequence_library中运行的sequence有次数说明,收到sequence_library中的变量max_random_count和min_random_count控制:

 可以看到,这两个值默认是10,也就是说,如果不加以设置,以UVM_SEQ_LIB_RAND运行的sequence_library,会随机执行10次sequence的发送,如果是UVM_SEQ_LIB_ITEM,则会产生10个sequence_item发送。

       sequence_library发送的机制其实是会选在min_random_count和max_random_count之间任意选择一个数来决定发送sequence的次数。可以通过设定这两个值改变sequence_library发送sequence的数量。可以在tc中通过uvm_configdb的方式改变值:

class my_tc extends base_test;
2.	       my_seq_library0  seq_lib;
3.	       `uvm_component_utils(my_tc)
4.	 ......
5.	       virtual function void build_phase(uvm_phase phase);
6.	            super.build_phase(phase);
7.	            seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	                   uvm_config_db#(uvm_seq_lib_mode)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.select_mode", UVM_SEQ_LIB_RANDC);
9.	                   uvm_config_db#(unsigned int)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.min_sequence_count", 5);
10.	                   uvm_config_db#(unsigned int)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.max_sequence_count", 20);
11.	            uvm_config_db#(uvm_object_wrap)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", seq_lib::type_id::get());
12.	        endfunction:build_phase
13.	
14.	 endclass

上述代码执行,会将sequence_library的select_mode设置为UVM_SEQ_LIB_RANDC模式,然后设定最大seq_count为20,最小seq_count为5,也就是发送sequence的数量介于5到20之间的随机值。

3.1 通过sequence library cfg控制sequence library的参数

事实上,除了通过config_db的方式设定sequence_library的两个主要的参数之外,还可以通过sequence library cfg进行归一化设定,sequence library cfg在uvm中的源码为:

其内部包含的主要变量就是selection_mode,min_random_count和max_random_count,可以看到在new函数中,可以直接设定这三个参数,实现参数的传递,在tc中,实例化uvm_sequence_library_cfg,然后通过new函数实现参数配置,再通过config_db的方式传递cfg,也可以实现对sequence_library参数的控制。

1.	 class my_tc extends base_test;
2.	       my_seq_library0  seq_lib;
3.	              uvm_sequence_library_cfg seq_lib_cfg;
4.	       `uvm_component_utils(my_tc)
5.	 ......
6.	       virtual function void build_phase(uvm_phase phase);
7.	            super.build_phase(phase);
8.	            seq_lib = my_seq_library0::type_id::create("seq_lib");
9.	            seq_lib_cfg = new("seq_lib_cfg", UVM_SEQ_LIB_RANDC, 5, 20);
10.	            uvm_config_db#(uvm_object_wrap)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", seq_lib::type_id::get());
11.	            uvm_config_db#(uvm_sequence_library_cfg)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.config", seq_lib_cfg);
12.	        endfunction:build_phase
13.	
14.	 endclass

 

3.2 实现控制sequence library参数的几种方法

       配置sequence_library的三个参数:select_mode,min_sequence_count,max_sequence_count的方式,可以通过在tc中利用config_db的方式传递值,也可以通过uvm_sequence_library_cfg的方式,在new函数中直接传递值,然后利用uvm_config_db将cfg传递给default_sequence.config,实现这三个参数的控制。

       实际上,因为这三个参数都是uvm_sequence_library基类的成员变量,tc中启动sequence_library之前,可以直接对这三个值进行赋值,也可以实现对参数的控制,例如如下tc代码:

1.	class my_tc extends base_test;
2.	       my_seq_library0  seq_lib;
3.	       `uvm_component_utils(my_tc)
4.	 ......
5.	       virtual function void build_phase(uvm_phase phase);
6.	            super.build_phase(phase);
7.	            seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	            seq_lib.select_mode=UVM_SEQ_LIB_ITEM;
9.	            seq_lib.min_sequence_count = 2;
10.	            seq_lib.max_sequence_count = 20;
11.	            uvm_config_db#(uvm_sequence_library_cfg)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.config", seq_lib_cfg);
12.	       endfunction:build_phase
13.	......
14.	endclass

或者在main_phase中调用start函数之前,对seq_lib进行赋值:

1.	class my_tc extends base_test;
2.	       my_seq_library0  seq_lib;
3.	       `uvm_component_utils(my_tc)
4.	 ......
5.	       virtual function void build_phase(uvm_phase phase);
6.	            super.build_phase(phase);
7.	            seq_lib = my_seq_library0::type_id::create("seq_lib");
8.	            ......
9.	            //uvm_config_db#(uvm_sequence_library_cfg)::set(this, "env.i_agt.sqr.main_phase", "default_sequence.config", seq_lib_cfg);
10.	       endfunction:build_phase
11.	
12.	       virtual task main_phase(uvm_phase phase);
13.	            super.main_phase(phase);
14.	            seq_lib.starting_phase = phase;
15.	            seq_lib.select_mode=UVM_SEQ_LIB_RANDC;
16.	            seq_lib.min_sequence_count = 2;
17.	            seq_lib.max_sequence_count = 20;
18.	            seq_lib.start(env.vseq.my_sqr, null, -1);
19.	       endtask:main_phase
20.	......
21.	endclass

这里对sequence_library的参数控制方法进行总结:

  • 首先可以通过uvm_config_db的方式直接传输这三个参数,参数传输的时候注意uvm_config_db参数化类的参数类型,以及“密钥”的类型(使用default_sequence.xxx)。
  • 其次可以通过例化uvm_sequence_library_cfg的方式,在构造函数new中直接传递这三个变量。然后通过uvm_config_db的方式将cfg传输。

最后,可以通过层次化的方式直接赋值,即seq_lib.xxx直接赋值的方式,可以在default_sequence启动之间赋值,也可以在调用start函数之前赋值。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值