UVM基础-config_db的用法

1.1 config_db的引入:

         一般的,在构建验证环境时,都会建立一层harness,作为testbench的顶层,内部包含了待测DUT,interface和一些check模块,以及运行整个UVM环境的run_test()函数。那么UVM的环境组件driver是如何得到这一组interface的,UVM提供了用于组件之间的变量交互机制-config_db机制。

       通常在testbench里,会通过config_db#(virtual my_if)::set的方式将interface发出,给到driver,在driver里通过config_db#(virtual my_if)::get的方式得到这一组interface,再执行驱动逻辑。如下图所示代码块:

1.	//TestBench Top
2.	initial begin
3.	      config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", vif);
4.	end
5.	//driver
6.	......
7.	my_if bus;
8.	......
9.	function void my_driver::build_phase(uvm_phase phase);
10.	      super.build_phase(phase);
11.	      config_db#(virtual my_if)::get(this, "", "vif", bus);
12.	......
13.	endfunction:build_phase;

一般我们将set的过程称之为寄信,而get的过程称之为收信,一般寄信的组件中,要说明寄给谁,而收信的组件,要执行寄信的“应答”过程,在这里我将其比作对密钥,密钥对上了,信就能收到。

1.2 config_db的编程规则

set的编程规则:以test_case寄给driver一个名为pkt_num为例:

config_db#(int)::set(this, “env.i_agt.drv”, “pkt_num”, 100)

       解析一下,config_db其实是一个参数化类,而SystemVerilog的参数化类是支持编程模板的,这个概念在C语言中很常见。而“#()”,其中括号里声明的类型就是当前要寄出的变量的类型,因为支持模板编程,因此这个类型可以是类,也可以是SV支持的任何类型的变量,set函数是config_db类里面的一个静态函数,因此可以通过“::”作用域运算符直接调用。set函数有4个参数:

第一个参数:表示当前要寄信的组件,一般是一个uvm_component类型的变量,但如果本身不是组件呢?例如在tb顶层去寄信,那么这个位置填null,或者填写uvm_root::get(),其实null会自动替换成uvm_root::get(),也就是UVM树形结构的最顶层。

第二个参数:第二个参数是一个字符串类型,表示要寄信的目标地址,是相对于第一个参数来说的,以当前实例为例,在test_case寄给driver,那么树形结构为test_case.env.i_agt.drv,这个参数相对于第一个参数设置,因此是“env.i_agt.drv”,值得注意的是,这个要体现uvm的树形结构,也就是说组件的实例化除了注册到factory机制后,实例化调用factory的create函数,传参第一个就是树的实例化名字,如果在i_agent里声明了一个my_driver drv的句柄,实例化的时候调用的是drv = my_driver::type_id::create(“m_driver”, this),那么第二个参数要写成“env.i_agt.m_driver”。

第三个参数:这也是一个字符串类型的参数,就是之前提到的密钥,也就是说,my_driver里的get函数第三个参数也应该是“pkt_num”,才能与这个set对上密钥,信才能收到,一般密钥体现寄信的内容即可。

第四个参数:这个参数是具体寄信的值。

       get编程规则:在driver中

config_db#(int)::get(this, “”, “pkt_num”, pkt_num)

       与set类似,#()里括号中表示要传递的变量的类型,get函数依旧包括四个参数:

第一个参数:表示当前要收信的组件,在driver中收信,那么就写为this。

第二个参数:这个参数是一个字符串类型的参数,与第一个参数一起使用,表示在uvm树形结构中,收信组件的位置,因为在driver中收信,第一个参数已经是this指向driver,那么第二个参数为空即可;如果第一个参数变为:this.m_parent,指向了driver的父类,那么第二个参数要写为:“drv”,相对于父类的路径。规则与set一致,但如果第一个参数写为null,那么第二个参数要写为“uvm_test_top.env.i_agt.drv”。

第三个参数:这个参数就是收信的密钥,要和寄信一致,才能正确的收到。

第四个参数:这个参数为收信组件中要被赋值的变量,也就是在get之后,会将driver中一个int类型的变量pkt_num赋值为100。

1.3 省略get语言

       在某些情况下,config_db的get语句可以省略,因为config_db实际上是需要组件在注册到factory中,或者object在注册到uvm_object_utils中的时候才能够使用config_db,那么注册在factory机制中的收信组件,当一个变量被写到field_automation中的时候,就可以省略get,比如如下的driver代码:

1.	class my_driver extends uvm_driver#(uvm_sequence_item);
2.	        int pkt_num;
3.	        `uvm_component_utils_begin(my_driver)
4.	            `uvm_field_int(pkt_num, UVM_ALL_ON)
5.	        `uvm_component_utils_end
6.	
7.	        extern function void new(string name="my_driver", uvm_component parent);
8.	        extern virtual function void build_phase(uvm_phase phase);
9.	        extern virtual function void connect_phase(uvm_phase phase);
10.	......
11.	        extern virtual task main_phase(uvm_phase phase);
12.	endclass
13.	
14.	function void my_driver::new(string name="my_driver", uvm_component parent);
15.	      super.new(name, parent);
16.	endfunction:new
17.	
18.	function void my_driver::build_phase(uvm_phase phase);
19.	      super.build_phase(phase);
20.	      `uvm_info(get_type_name(), $sformatf("pkt num is %d", pkt_num), UVM_HIGH);
21.	......
22.	endfunction:build_phase

使用省略get语法的使用方法时应该注意:

  1. 在收信组件中要声明一个变量,这个变量的名字要和set过程的密钥一摸一样。
  2. 收信组件首先要注册到factory机制中,这个声明的变量,要注册到field_automation机制中;
  3. 在build_phase中首先要调用super.build_phase,也就是基类的build_phase,因为注册到factory机制中要收信的变量,会在基类的build_phase中调用get。

因此,良好的编码习惯为,set函数的密钥参数,就应该和收信组件的变量一致,不要搞特殊的密钥,导致代码维护困难。

1.4 config_db对通配符的支持

       config_db set的第三个参数支持通配符操作,比如一个最常见的场景,一个input interface不但要发给driver,同样也要发给monitor,那么通常的写法是:

1.	config_db #(virtual my_if)::set(uvm_root::get, "uvm_test_top.env.i_agt.drv", "pkt_num", in_vif);
2.	config_db #(virtual my_if)::set(uvm_root::get, "uvm_test_top.env.i_agt.mon", "pkt_num", in_vif);
3.	config_db #(virtual my_if)::set(uvm_root::get, "uvm_test_top.env.o_agt.mon", "pkt_num", o_vif);

可以使用通配符写为:

1.	config_db #(virtual my_if)::set(uvm_root::get, "uvm_test_top.env.i_agt.*", "pkt_num", in_vif);
2.	config_db #(virtual my_if)::set(uvm_root::get, "uvm_test_top.env.o_agt.*", "pkt_num", o_vif);

第二个参数可以用*代替。进一步,前面的参数也可以用通配符:

1.	config_db #(virtual my_if)::set(uvm_root::get, "*i_agt.*", "pkt_num", in_vif);
2.	config_db #(virtual my_if)::set(uvm_root::get, "*o_agt.*", "pkt_num", o_vif);

但一般不建议这样用,因为通配符用的越多,有可能会造成一些想不到的异常,比如在某个组件中本来不想收到来自tc的pkt_num,而是用自己的,因为tc中用了通配符,导致pkt_num变化。一般提倡将寄信的路径显示的写明。

1.5 uvm_object类型组件对config_db的支持

       在uvm_component中使用config_db很明确,但是一个uvm_object类可否使用config_db呢? 答案是可以的,但是也存在一个问题,就是config_db的第二个参数的路径应该如何获取,其实uvm_object类中提供了一个获取路径的函数,get_full_name(),比如在sequence中调用这个函数,打印的是:uvm_test_top.env.i_agt.sqr.case0_sequence,为什么路径显示的是sqr?其实也很好理解,就是一个sequence要注定在某个sequencer上启动,因此,sequencer的路径下存在sequence也很合理。因此如果要在sequence中使用get方法,那么要这么写:

config_db#(bit)::get(null, get_full_name(), “ecc_error”, ecc_error);

       如果在tc中寄信,那么应该这么写:

config_db#(bit)::set(this, “env.i_agt.sqr*”, “ecc_error”, 1’b1);

       这里注意的是使用了通配符,原因是一个sequence的名字一般是不固定的, 而且如果用default_sequence启动的化,名字更加不固定。所以这里要使用通配符。

在非uvm_component组件中使用config_db使用总结:

  1. 同样这个uvm_object类型的组件要注册到`uvm_object_utils;
  2. 在寄信的组件中要使用通配符,因为一般情况下,非组件是有声明周期的,而且名称不固定
  3. 在收信的uvm_object中,因为无法确认其路径,因此使用基类中国的函数:get_full_name()获取,此时get的第一个参数不能是this指针,而要写成null或者uvm_root::get()。
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
UVM中的config_db机制是一种方便的配置管理机制,可以在测试用例中动态地配置不同组件之间的参数。它允许用户将配置信息存储在单个数据库中,并在需要时从中检索。 config_db机制的核心是一个名为uvm_config_db的类,它提供了一些静态方法,用于将配置信息存储在数据库中、从数据库中检索配置信息和删除配置信息。每个配置信息都有一个名称和一个通用的数据类型,可以是任意类型的数据结构,包括简单的整数和字符串,以及更复杂的对象和指针。 config_db机制可以用于多种情况,例如: 1. 在测试用例中配置测试环境中的组件; 2. 在测试用例中配置测试用例本身; 3. 在测试用例中配置测试运行时环境(如时钟周期)。 下面是一个例子,展示如何使用config_db机制来配置两个组件之间的参数: ```systemverilog // 存储配置信息 uvm_config_db#(int)::set(null, "env.agent1.config", "data", 100); uvm_config_db#(string)::set(null, "env.agent2.config", "data", "hello"); // 从数据库中检索配置信息 int my_int; string my_string; uvm_config_db#(int)::get(null, "env.agent1.config", "data", my_int); uvm_config_db#(string)::get(null, "env.agent2.config", "data", my_string); ``` 在上面的例子中,我们使用uvm_config_db类的set方法将一个整数值和一个字符串值存储在了数据库中,并使用get方法从数据库中检索这些值。注意,我们使用了不同的名称("env.agent1.config"和"env.agent2.config")来区分不同的配置信息。这些名称应该在测试用例中被定义为常量或宏,以便在整个测试用例中使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值