[CU]config_db机制3-uvm_config_db使用注意事项

注1:该篇文章侧重于config_db机制的使用;

1. config机制成对出现

1.1 简单示例

如在某个case(派生自uvm_test)的build_phase中可以做如下设置: 

1 uvm_config_db#(int)::set(this,"env.agent.driver","pre_num_max",100);

那么在driver的build_phase中需要:

1 uvm_config_db#(int)::get(this,"","pre_num_max",pre_num_max);

1.2 示例解释

(1) uvm_config_db中set和get都是静态函数,可用双冒号形式调用.

1   static function void set(uvm_component cntxt,
2                            string inst_name,
3                            string field_name,
4                            T value);
5   static function bit get(uvm_component cntxt,
6                           string inst_name,
7                           string field_name,
8                           inout T value);

(2) uvm_config_db::set的参数解释:

1 initial begin
2     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.drv","vif",input_if);
3 end
4 
5 initial begin
6     uvm_config_db#(virtual my_if)::set(uvm_root::get(),"uvm_test_top.env.i_agt.drv","vif",input_if);
7 end

注1:在top module中通过config_db机制的set函数设置virtual interface时,set的第一个参数为null; 在这种情况下,UVM会自动把第一个参数替换为uvm_root::get(),即uvm_top;

(2.1) set的第一个参数用以说明是哪个component对pre_num_max进行设置,通常是一个uvm_component的指针,一般使用填写this; 

(2.2) set的第二个参数表示从调用uvm_config_db::set的地方看下去,要设置的变量所在的component的路径; set的前两个参数联合起来组成路径;

(2.3) set的第三个参数表示一个记号,用于说明这个值是传给driver中的哪个变量的; 

(2.4) set的第四个参数是要设置的值;

(3) uvm_config_db::get的参数解释:

(3.1) get的第一个参数一般是this即可;

(3.2) get的第二个参数填写一个空的字符串;

(3.3) get的第三个参数就是set中的第三个参数,二者必须一致;

(3.4) get的第四个参数则是要设置的变量;

1 uvm_config_db#(int)::set(this,"env.i_agt.drv","p_num",100);
2 uvm_config_db#(int)::get(this,"","p_num",pre_num);

注1:get函数中第三个参数可以与get函数中第四个参数不一样(但是最好一样,这种情况下,如果再满足其他条件,可以省略get语句);

2. 省略get的config

(1) 虽然通常要求set与get成对出现,但是在某些特定情况下,get是可以省略的.

(2) 实现原理: build_phase内的super.build_phase(phase)在满足以下特定条件的情况下,可以完成get的功能(super.build_phase中实现的自动get,uvm_component的apply_config_settings实现自动get);

特定条件1:将正常情况下需要执行get操作的类注册到factory;

特定条件2:使用field_automation机制把要get的变量注册;

特定条件3:set的第三个参数必须与要get的变量的名字相一致;

(3) 示例

 1 class mac_driver extends uvm_driver#(mca_transaction);
 2     ...
 3     int pre_num;
 4     int pre_num_min;
 5     int pre_num_max;
 6 
 7     `uvm_component_utils_begin(mac_driver)
 8         `uvm_field_int(pre_num_min,UVM_ALL_ON)
 9         `uvm_field_int(pre_num_max,UVM_ALL_ON)
10     `uvm_component_utils_end
11 
12     function void build_phase(uvm_phase phase);
13         super.build(phase);
14         //uvm_config_db#(int)::get(this,"","pre_num_max",pre_num_max);
15         //uvm_config_db#(int)::get(this,"","pre_num_min",pre_num_min);
16     endfunction
17 
18 endclass

3. 跨层次的多重set(build_phase的set)

注1:后面需要补充非build_phase的set相关内容,可参考公众号-芯片学堂;

假如set多次,get一次,那么最终get到的是哪个set值呢?

(1) 首先看set的优先级(层次越高,set的优先级越高);

(2) 其次看时间先后;

比如,在uvm_test_top和env中分别有以下set语句:

1 uvm_config_db#(int)::set(this,"env.agent.driver","pre_num_max",100);
2 uvm_config_db#(int)::set(this,"agent.driver","pre_num_max",999);

uvm_test_top的层次高于env,所以uvm_test_top中的set优先级高.因为越往上,越接近用户,方便用户控制.

4. 同一层次的多重set(build_phase的set)

当跨层次看待问题时,高层次的set优先; 当处于同一层次时,则是时间优先.

1 uvm_config_db#(int)::set(this,"env.agent.driver","pre_num_max",100);
2 uvm_config_db#(int)::set(this,"env.agent.driver","pre_num_max",109);

driver最终get的值会是109.

5. 非直线的设置与获取

(1) 如在scoreboard中,对driver的某些变量使用config_db机制进行设置,则称为非直线设置;

 1 //my_scoreboard.sv
 2 function void my_scoreboard::build_phase(uvm_phase phase);
 3     ...
 4   uvm_config_db#(int)::set(this.m_parent,"i_agt.drv","pre_num",200);
 5     ...
 6 endfunction
 7 
 8 //my_scoreboard.sv
 9 function void my_scoreboard::build_phase(uvm_phase phase);
10     ...
11     uvm_config_db#(int)::set(uvm_root::get(),"uvm_test_top.env.i_agt.drv","pre_num",200);
12     ...
13 endfunction

(2) 存在的问题: UVM没有明文指出同一级别的build_phase的执行顺序,所以当my_driver在获取参数值时,my_scoreboard的build_phase可能已经执行了,也可能没有执行;所以,这种非直线的设置,存在一定风险;

6. config机制对通配符的支持

(1) 在config_db::set操作时,其第二个参数可以提供完整的路径,也可以不提供完整的路径;

注1:可以将config_db的set放到一个module的initial begin...end块内,并通过bind的方式将该module在top module内例化;

注2:下图中使用通配符的code中,i_agt是否能看到该资源?需要确认下(可以!);

 1 //top_tb.sv
 2 //不使用通配符
 3 initial begin
 4     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.drv","vif",input_if);
 5     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt.mon","vif",input_if);
 6     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.o_agt.mon","vif",output_if);
 7 end
 8 
 9 //使用通配符
10 initial begin
11     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.i_agt*","vif",input_if);
12     uvm_config_db#(virtual my_if)::set(null,"uvm_test_top.env.o_agt*","vif",output_if);
13 end
14 
15 //使用通配符
16 initial begin
17     uvm_config_db#(virtual my_if)::set(null,"*i_agt*","vif",input_if);
18     uvm_config_db#(virtual my_if)::set(null,"*o_agt*","vif",output_if);
19 end

7. config_db与变量的变化

注:以下是仿真得出的结论;

(1) 如果通过config_db进行int变量的set/get,发现一次set后, int变量接着发生了变化,这种变化无法通过config_db::get得到; 只能在每次变化后,重新set,并且重新get;

(2) 如果通过config_db进行类变量/virtual interface的set/get,发现一次set后,类变量/virtual interface的内部成员变量值发生了变化,不需要重复get,可以直接通过已经get过一次的句柄/virtual interface发现其内部成员变量的变化;

 

posted on 2021-11-15 15:30  知北游。。  阅读(1865)  评论(0编辑  收藏  举报

导航