UVM验证的优势
1.模块化可重用性:该验证方法被分为模块化组件(驱动程序,序列发生器,代理,env等),可以将组件级别之间的组件重用于多单元或芯片级别验证以及跨项目。
2.将测试用例与验证平台分开:测试用例与实际的测试平台层次结构分开,因此可以在不同的单元或跨项目中重用激励
3.独立于仿真器:所有仿真器都支持基类库和方法,因此不依赖于任何特定的仿真器
4. 更好地控制激励产生:sequence方法可以很好地控制激励的产生,有一些方法可以开发序列 包括随机化,sequence机制提供了良好的控制和扩展激励生成能力
5.config机制:config机制简化了具有深层次结构的对象的配置,config机制有助于根据验证环境轻松配置不同的测试平台组件,而无需担心任何组件在验证环境中的深度。
6.factory机制:factory机制简化了组件的修改,使用工厂创建每个组件使他们可以在不同的测试或环境中被覆盖,而不需更改底层代码库。
工厂机制
工厂的意义
UVM工厂的存在就是为了更方便地替换验证环境中的实例或者注册了的类型,同时工厂的注册机制也带来了配置的灵活性。UVM的验证环境构成可以分为两部分,—部分构成了环境的层次, 这部分代码是通过uvm_Component类完成,另外—部分构成了环境的属性(例如配置)) 和数据传输,这一部分通过 uvm_object类完成
这两种类的集成关系从UVM类库地图可以看到, uvm_Component类继承于uvm_object类,而这两种类也是进出工厂的主要模具和生产对象。这使得在不修改原有验证境层次和验证包的同时实现了对环境内部组件类型或者对象的覆盖。
uvm_component 和uvm_object
验证环境的不动产,大致包含: generator 、 stimulator 、monitor 、agent 、checker/reference model 、environment 、test 。这些组件在uVm_Component的子类中均有对应的组件。
例化
每一个uvm_{component, object]在例化的时候都应该给予一个名字(string) ,“full name”指的是component所处的完整层次结构。创建component或者object的方法如下:
创建(create)
一般来说运用factory的步骤可分为 :将类注册到工厂 、在例化前设置覆盖对象和类型(可选的) 、对象创建。 在两种类comp 1和obj 1的注册中,分别使用了UVM宏,这两个宏做的事情就是将类注册到factory中,factory是独有的,即有且只有一个,这 保证了所有类的注册都在一个“机构” 中
uvm_coreservice_t类
该类内置了UVM世界核心的组件和方法,它们主要包括 :唯一的uvm_factory(该组件用来注册、覆盖和例化) ;全局的report_server(该组件用来做消息统筹和报告 );全局的tr_database(该组件用来记录transaction记录)。该类并不是uvm_component或者uvm_object,它也并没有例化在UM不境中,而是独立于UVM不境之外的。
注册宏 `uvm_{component, object}_utils
uvm_component_utils用来注册组件类uvm_component,uvm_object_utils用来注册核心基类uvm_object
对于注册,并不是真正地将一个抽象的类型 (空壳) 放置在什么地方 而是通过例化该类的对象来完成。由于一种类型在通过宏调用时只注册一次,那么在不考虑覆盖的情况下 uvm_default_factory就将每一个类对应的对象都放置到了factory的字 典当中。
注册之后的对象创建
uvm_component和uvm_object在创建时虽然都需要调用create() 函数,但最终建出来的uvm_component是会表示在UVM层次构中的,而uvm_object则不会显示在层次中。
uvm_compnent::new(name,parent)保留两个参数,就是为了通过类似“钩子”的做法,一层层由底层勾住上一层,这样就能够将 整个UVM结构串接起来;
uvm_object::new(name)则没有parent参数,因此也不会显示在UVM层次中,只能作为Configuration或者transaction等用来做传递的配置结构体或者抽象数据传输的数据结构体,成为 uvm_component的成员变量。
与工厂相关的方法
覆盖方法
覆盖机制可以将其原来所属的类型替换为另外一个新的类型。 在覆盖之后,原本用来创建原属类型的请求,将由工厂来创建新的替换类型。无需再修改原始代码,继而保证了原有代码的封装性。新的替换类型必须与被替换类型相兼容,否则稍后的句柄赋值将失败,所以使用继承 。
要想实现覆盖特性,,原有类型和新类型身需要注册。 当使用create()来创建对象时 。工厂会检查,是否原有类型被覆盖。如果是,那么它会创建一个新类型的对象。如果不是,那么它会创建一个原有类型的对象。
覆盖发生时,可以使用“类型覆盖”或者“实例覆盖” ,类型覆盖指UVM层次结构下的所有原有类型都被覆盖类型所替换。 实例覆盖指,在某些位置中的原有类型会被覆盖类型所替换。
set_type_override()
set_inst_override()
覆盖实例
module factory_override;
import uvm_pkg::*;
`include "uvm_macros.svh"
class comp1 extends uvm_component;
`uvm_component_utils(comp1)
function new(string name="comp1",uvm_component parent=null);
super.new(name,parent);
$display($sformatf("comp1::%s is created",name));
endfunction:new
virtual function void hello(string name);
$display($sformatf("comp1::%s said hello!",name));
endfunction
endclass
class comp2 extends comp1;
`uvm_component_utils(comp2)
function new(string name="comp2",uvm_component parent=null);
super.new(name,parent);
$display($sformatf("comp2::%s is created",name));
endfunction:new
function void hello(string name);
$display($sformatf("comp2::%s said hello!",name));
endfunction
endclass
comp1 c1,c2;
initial begin
comp1::type_id::set_type_override(comp2::get_type());
c1=new("c1");
c2=comp1::type_id::create("c2",null);
c1.hello("c1");
c2.hello("c2");
end
endmodule
输出结果:
comp1::c1 is created
comp1::c2 is created
comp2::c2 is created
comp1::c1 said heiio!
comp2::c1 said heiio!
c1用的是new而没有通过工厂,所以C1没有替换,而C2通过工厂,所以C2替换了