Q10:UVM从哪里启动?
(1)在导入 uvm_pkg 文件时,会自动创建 uvm_root 所例化的对象 uvm_top,UVM 顶层的类会提供 run_test()方法充当 UVM 世界的核心角色,通过uvm_top 调用 run_test()方法。
(2)在环境中输入 run_test 来启动 UVM 验证平台,run_test 语句会创建一个 my_case0 的实例,得到正确的 test_name。
(3) 依次执行 uvm_test 容器中的各个 component 组件中的 phase 机制,按照顺序:
- build-phase(自顶向下构建 UVM 树)
- connet_phase(自底向上连接各个组件)
- end_of_elaboration_phase
- start_of_simulation_phase
- run_phase() objection 机制仿真挂起,通过 start 启动 sequence(每个 sequence 都有一个 body 任务。当一个 sequence 启动后,会自动执行sequence 的 body 任务。)。等到 sequence 发送完毕则关闭 objection,结束run_phase()。
(UVM_objection 提供 component 和 sequence 共享的计数器,当所有参与到 objection 机制中的组件都 drop objection 时,计数器 counter才会清零,才满足 run_phase()退出的条件) - 执行后面的 phase。
Q11:接口怎么传递到验证环境中?
-
通过uvm_cofig_db机制配置,可以将virtual interface传递到环境中。
-
虽然SV可以通过层次化的interface的索引完成传递,但是这种传递方式不利于软件环境的封装和复用。通过使用uvm_config_db配置机制来传递接口,可以将接口的传递与获取彻底分离开。
-
接口传递从硬件世界到UVM环境可以通过uvm_config_db来实现,在实现过程中应当注意:
- 接口传递应发生在run_test()之前。这保证了在进入build_phase之前,virtual interface已经被传递到uvm_config_db中。
- 用户应当把interface与virtual interface区分开来,在传递过程中的类型应当为virtual interface,即实际接口的句柄。
Q12:UVM的优势。
UVM 其实是 SV 的一个封装,将我们在搭建测试平台过程中的一些重复性和重要的工作进行封装,从而使我们能够快速的搭建一个需要的测试平台,并且可重用性还高。但是 UVM 又不仅仅是封装。
11 uvm_config_db机制
常见使用方式:
- 传递virtual interface到环境中;
- 配置单一变量值,例如int、string、enum等;
- 传递配置对象(config_object)到环境。
11.1 vif的传递
interface intf1; //接口定义
logic enable = 0;
endinterface
class comp1 extends uvm_component; //组件配置接口
`uvm_component_utils(comp1)
virtual intf1 vif; //接口声明
...
function void build_phase(uvm_phase phase);
if(!uvm_config_db #(virtual intf1)::get(this,"","vif",vif)) begin //**3. 获取配置接口vif = intf**
`uvm_error("GETVIF","no virtual interface is assigned")
end
`uvm_info("SETVAL",$sformatf("vif.enable is %b before set",vif.enable),UVM_LOW)
vif.enable = 1;
`uvm_info("SETVAL",$sformatf("vif.enable is %b after set",vif.enable),UVM_LOW)
endfunction
endclass
class test1 extends uvm_test; //测试用例层,可在此进行接口配置,也可在顶层配置
`uvm_component_utils(test1)
comp1 c1;
...
endclass
intf1 intf(); //**1. 接口配置前,例化借口**
initial begin
uvm_config_db #(virtual intf1)::set(uvm_root::get(),"uvm_test_top.c1","vif",intf) //**2. 启动接口配置**
run_test("test1"); //在run_test()之前完成接口配置
end
11.2 配置单一变量值,例如int、string、enum等;
各个 test 中,可以在 build_phase 阶段对底层组件的各个变量加以配置,进而在环境例化之前完成配置,使得环境可以按照预期运行。
class comp1 extends uvm_component; //组件
`uvm_component_utils(comp1)
int val1 = 1;
string str1 = "null";
...
function void build_phase(uvm_phase phase); //在build_phase阶段进行配置
`uvm_info("SETVAL",$sformatf("val1 is %d before get",val1),UVM_LOW)
`uvm_info("SETVAL",$sformatf("str1 is %d before get",str1),UVM_LOW)
uvm_config_db #(int)::get(this,"","val1",val1); //使用get()方法获取配置
uvm_config_db #(string)::get(this,"","str1",str1);
`uvm_info("SETVAL",$sformatf("val1 is %d after get",val1),UVM_LOW)
`uvm_info("SETVAL",$sformatf("str1 is %d after get",str1),UVM_LOW)
endfunction
endclass
class test1 extends uvm_test; //测试用例层, 启动配置
`uvm_component_utils(test1)
comp1 c1;
...
function void build_phase(uvm_phase phase);
uvm_config_db #(int)::set(this,"c1","val1",100); //使用set()方法获取配置
uvm_config_db #(string)::set(this,"c1","str1","comp1");
c1 = comp1::type_id::create("c1");
endfunction
endclass
11.3 config object对象传递;
- 在test配置中,需要配置的参数不只是数量多,可能还分属于不同的组件。对这么多层次的变量做出类似上边的单一变量传递,需要更多的代码,容易出错且不易复用。
- 如果整合各个组件中的变量,将其放置在一个uvm_object中,再对中心化的配置对象进行传递,将有利于整体环境的修改维护,提升代码的复用性。
class config1 extends uvm_object; //**1. 创建一个配置类,将需要配置的变量放于其中**
`uvm_object_utils(config1)
int val1 = 1;
int str1 = "null";
...
endclass
class comp1 extends uvm_component; //组件
`uvm_component_utils(comp1)
config1 cfg ; //声明配置类句柄
...
function void build_phase(uvm_phase phase);
uvm_object tmp; //声明类句柄
uvm_config_db #(uvm_object)::get(this,"","cfg",tmp); //**3. 获取变量配置**
void`($cast(cfg,tmp)); //类型转韩,将传到tmp中的值赋给cfg
`uvm_info("SETVAL",$sformatf("cfg.val1 is %d after get",cfg.val1),UVM_LOW)
`uvm_info("SETVAL",$sformatf("cfg.str1 is %d after get",cfg.str1),UVM_LOW)
endfunction
endclass
class test1 extends uvm_test; //测试用例层, 启动配置
`uvm_component_utils(test1)
comp1 c1, c2;
config1 cfg1, cfg2;
...
function void build_phase(uvm_phase phase);
cfg1 = config1::type_id::create("cfg1");
cfg2 = config1::type_id::create("cfg2");
c1 = comp1::type_id::create("c1");
c2 = comp1::type_id::create("c2"); //创建对象
cfg1.val1 = 30;
cfg1.str1 = "c1";
cfg2.val1 = 50;
cfg2.str1 = "c2";
uvm_config_db #(uvm_object)::set(this,"c1","cfg",cfg1); //**2. 启动变量配置**
uvm_config_db #(uvm_object)::set(this,"c2","cfg",cfg2); //启动变量配置
endfunction
endclass