[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发现其内部成员变量的变化;