概述
1 类库地图
UVM 验证方法学作为所有方法学的融合之体,其初衷是将验证过程中可以重用和标准化的部分规定在其类库当中,以一种标准化的方式减轻验证人员构建环境的负担。
验证环境的共同需求:
1. 组件的创建和访问;
2.环境的结构构建,各组件之间的连接和运行;
3.不同阶段的顺序安排;
4.激励的生成、传递和控制;
5.测试的报告机制。
UVM 核心机制:
1.核心基类:提供最底层的支持,包括一些基本的方法,如复制,创建,比较和打印。
2.工厂(factory)类:提供注册环境组件,创建环境组件和覆盖组件类型的方法。
3.事务(transaction)和序列(sequence)类:用来规定在TLM(transaction level model)传输管道中的数据类型和数据生成方式。
4.结构创建(structure creation)类
5.环境组件(environment component)类:构成验证结构的主要部分,组件之间的嵌套关系通过层层例化和连接形成结构层次关系。
6.通信管道(channel)类:实现数据储存。
7.信息报告(message report):将UVM 报告信息一致化,便于整体的控制和过滤。
8.寄存器模型(register model):完成对寄存器存储的建模,访问和验证。
9.线程同步(thread synchronization)类:同步是传递更多的信息。
10.事务接口(transaction interface)类:实现组件之间的通信。
2 工厂机制
UVM工厂的存在就是为了更方便地覆盖验证环境中的实例或者注册了的类型,同时工厂的注册机制也带来了配置的灵活性。
UVM 的验证环境可以分为两部分,一部分构成了环境的层次,这部分代码通过uvm_component类实现;另一部分构成了环境的属性(配置)和数据传输,这部分代码通过uvm_object类实现。uvm_ component类继承于uvm_object类。
参照SV模块的组件概念,即验证环境的不动产,大致包含:
generator stimulator monitor agent checker/refenence model environment test
这些组件在uvm_component的子类中均有对应的组件;
而在SV中的非固定资产即TLM transaction,从generator流向stimulator 的数据包,这些在UVM 中统一由uvm_object表示。
注册、创建实例:
class comp1 extends uvm_component;//定义comp1类,作为子类继承uvm_component;
`uvm_component_utils(comp1) //注册范式
function new(string name ="comp1",uvm_component parent=null);//构建函数范式
super.new(name, parent); //继承父类new函数
$display($sformatf("%s is created", name));
endfunction:new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction:build_phase
endclass
class obj1 extends uvm_object; //定义obj1类,作为子类继承uvm_object;
`uvm_object_utils(obj1) //注册范式
function new(string name ="obj1"); //构建函数范式
super.new(name); //继承父类new函数
$display($sformatf("%s is created", name));
endfunction:new
endclass
comp1 c1,c2;
obj1 o1,o2;
initial begin
c1=new("c1"); //SV 中的例化方式
o2=new("o2");
c2=comp1::type_id::creat("c2",null); //UVM世界的例化创建方式,component范例
o2=obj1::type_id::creat("o2"); //UVM世界的例化创建方式,object范例
end
注册component/object范式:
uvm_{component,object}_utils(comp/obj_type);
创建component范式:
comp_type::type_id::create(string name, uvm_component parent);
创建object范式:
object_type::type_id::create(string name);
一般运用工厂的步骤:
1. 将类注册到工厂;
2. 在例化前设置覆盖对象和类型;(可选)
3.对象创建。
创建对象时,需要结合工厂的注册和覆盖机制来决定应该使用component还是object来创建对象。
uvm_component::new(name,parent)保留两个参数,一种类似与钩子的做法,一层层由底层勾住上一层,将整个UVM 结构串起来。
uvm_object::new(name)没有parent参数,因此也不会显示在UVM 层次中,只能作为transaction和configuration用来做抽象数据传输的数据结构体和传递的配置结构体。
除了使用component/object来创建实例,factory也提供了创建范例:
creat_component/object_by_name( )
creat_component/object_by_type( )
uvm_component/object 提供了配合工厂注册,创建和覆盖的相关方法:
create()
create_component( )
get ( )
get_type_name()
set_inst_override()
set_type_override( )
3 覆盖方法
覆盖机制将其原来某些类型替换为一个新的类型
在覆盖之后,原本用来创建原属类型的请求,将由工厂来创建新的替换类型。
无需修改原始代码,继而保证的原始代码的封装性;
新的替换类型必须与被替换类型相兼容,否则稍后的句柄赋值将失败,所以使用继承。
要想实现覆盖特性, 原有类型和新类型均需要注册。
覆盖发生时, 可以使用类型覆盖或者实例覆盖:
• 类型覆盖指,UVM层次结构下的所有原有类型都被覆盖类型所替换;
• 实例覆盖指, 在某些位置中的原有类型会被覆盖类型所替换。
//类型覆盖
set_type_override()
static function void set_type_override(uvm_object_wrapper override_type,bit replace=1);
uvm_object_wrapper override_type
并不是一个实际的句柄,是注册过后的某一个类在工厂中注册时的句柄,可通过new_type::get_type()找到;
bit replace=1
1表示如果已经有覆盖存在, 那么新的覆盖会替代旧的覆盖。0表示 如果已经有覆盖存在, 那么该覆盖将不会生效。
rig_type::tpe_id::set_type_override(new_type::get_type());
//实例覆盖
set_inst_override()
static function void set_type_override(uvm_object_wrapper override_type,string inst_path,uvm_component parent =null);
• string inst_path指向的是组件结构的路径字符串
• uvm_component parent=null
如果缺省, 表示使用inst_path 内容为绝对路径
如果有值传递, 则使用 {parent.get_full_name(),'.', inst_path}来作为目标路径。
orig_type:: type_id::set_inst_override(new_type::get_type(), "orig_inst_path")
覆盖实例:
module factory_override;
import uvm_pkg::*;
`include "uvm_macros.svh"
class comp1 extends uvm_component;//定义comp1类,作为子类继承uvm_component;
`uvm_component_utils(comp1) //注册范式
function new(string name ="comp1",uvm_component parent=null);//构建函数范式
super.new(name, parent); //继承父类new函数
$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;//定义comp1类,作为子类继承comp2;
`uvm_component_utils(comp2) //注册范式
function new(string name ="comp2",uvm_component parent=null);//构建函数范式
super.new(name, parent); //继承父类new函数
$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=com1::type_id::create("c2",null); //创建对象
c1.hello("c1");
c2.hello("c2");
end
输出结果:
compl:: cl is created
compl:: c2 is created
comp2:: c2 is created
compl:: cl said hello!
comp2:: c2 said hello!
comp2覆盖了comp1类型解析:
comp1:: type_id::set_type_override(comp2::get_type());
• 接着若对c1和c2对象进行了创建,可以从输出结果看到,c1的所属类型仍然是 comp1, c2的所属类型则变为了comp2。这说明了factory的覆盖机制只会影响通过factory注册并且创建的对象。
• 所以通过type_id::create( )和factory的类型覆盖可以实现对象所属类型在例化时的灵活替换。
• 在例化c2之前,首先应该用comp2来替换comp1的类型。只有先完成了类型替换,才可以在后面的例化时由factory选择正确的类型。
• 在后面发生了类型替换以后,如果原有的代码不做更新,那么c2句柄的类型仍然为comp1, 但却指向了comp2类型的对象。这就要求,comp2应该是comp1的子类,只有这样,句柄指向才是安全合法的。
• c2在调用hello()方法时,由于首先是comp1类型,那么会查看comp1::hello(),又由于该方法在定义时被指定为虚函数,这就通过了多态性的方法调用,转而调用了comp2::hello()函数。因此,显示的结果也是"comp2:: c2 said hello!"
覆盖发生在创建之前,层次越高配置覆盖优先级越高。
首先需要知道, 有不止一个类提供与覆盖有关的函数, 然而名称与参数列表可能各不相同:
• uvm _ component::set_{type, inst}_override{_by_type}
• uvm _ component:,_registry: :set_{type, inst}_override
• uvm_object_registry: :set_{type, inst}_override
• uvm_factory:: set._{ type , inst}_override
整个UVM世界的构建, 离不开factory的三个核心要素: 注册、 创建和覆盖
最后,笔者根据实验内容新加一部分代码,覆盖该文的所有重点:
package factory_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
class trans extends uvm_object;
bit[31:0] data;
`uvm_object_utils(trans)
function new(string name = "trans");
super.new(name);
`uvm_info("CREATE", $sformatf("trans type [%s] created", name), UVM_LOW)
endfunction
endclass
class bad_trans extends trans;
bit is_bad = 1;
`uvm_object_utils(bad_trans)
function new(string name = "trans");
super.new(name);
`uvm_info("CREATE", $sformatf("bad_trans type [%s] created", name), UVM_LOW)
endfunction
endclass
class unit extends uvm_component;
`uvm_component_utils(unit)
function new(string name = "unit", uvm_component parent = null);
super.new(name, parent);
`uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
endfunction
endclass
class big_unit extends unit;
bit is_big = 1;
`uvm_component_utils(big_unit)
function new(string name = "bit_unit", uvm_component parent = null);
super.new(name, parent);
`uvm_info("CREATE", $sformatf("big_unit type [%s] created", name), UVM_LOW)
endfunction
endclass
class top extends uvm_test;
`uvm_component_utils(top)
function new(string name = "top", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
endtask
endclass
class object_create extends top;
trans t1, t2, t3, t4;
`uvm_component_utils(object_create)
function new(string name = "object_create", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
uvm_factory f = uvm_factory::get(); // get singleton factory
super.build_phase(phase);
t1 = new("t1"); // direct construction
// TODO-1.1 Please use the given kinds of create methods for uvm_objects
// create t2 with method trans::type_id::create(string name, uvm_component parent = null);
t2 = trans::type_id::create("t2");
// create t3 with method uvm_factory method f.create_object_by_type(...) as below
// function
// uvm_object create_object_by_type (uvm_object_wrapper requested_type,
// string parent_inst_path="",
// string name="");
void'($cast(t3,f.create_object_by_type(trans::get_type(),get_full_name(),"t3"))); // factory method
// create t4 with method create_object(...) as below
// function uvm_object create_object (string requested_type_name,
// string name="");
void'($cast(t4,create_object("trans","t4")));// pre-defined method inside component
endfunction
endclass
class object_override extends object_create;
`uvm_component_utils(object_override)
function new(string name = "object_override", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
// replace trans type with bad_trans type with method
// function void set_type_override_by_type
// (uvm_object_wrapper original_type,
// uvm_object_wrapper override_type,
// bit replace=1)
set_type_override_by_type(trans::get_type(),bad_trans::get_type());
super.build_phase(phase);
endfunction
endclass
class component_create extends top;
unit u1, u2, u3, u4;
`uvm_component_utils(component_create)
function new(string name = "component_create", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
uvm_factory f = uvm_factory::get(); // get singleton factory
super.build_phase(phase);
u1 = new("u1"); // direct construction
// TODO-1.2 Please use the given kinds of create methods for uvm_objects
u2 = unit::type_id::create("u2",this);
// create u2 with method unit::type_id::create(string name, uvm_component parent = null);
// create u3 with method uvm_factory method f.create_component_by_type(...) as below
// function
// uvm_component create_component_by_type (uvm_object_wrapper requested_type,
// string parent_inst_path="",
// string name,
// uvm_component parent);
void'($cast(u3,f.create_component_by_type(unit::get_type(),unit::get_full_name(),"u3",this)));
// create u4 with method create_component(...) as below
// function uvm_component create_component (string requested_type_name,
// string name)
void'($cast(u4,create_component("unit","u4")));
endfunction
endclass
class component_override extends component_create;
`uvm_component_utils(component_override)
function new(string name = "component_override", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
// replace unit type with big type with method
// function void set_type_override(string original_type_name,
// string override_type_name,
// bit replace=1);
set_type_override("unit","big_unit");
super.build_phase(phase);
endfunction
endclass
endpackage
module factory_mechanism;
import uvm_pkg::*;
`include "uvm_macros.svh"
import factory_pkg::*;
initial begin
run_test(""); // empty test name
end
endmodule
最后
以上就是无限小笼包为你收集整理的UVM-- 类库地图、工厂机制及覆盖方法的全部内容,希望文章能够帮你解决UVM-- 类库地图、工厂机制及覆盖方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复