UVM DAY1
《UVM》白皮书第一章,简单了解一下UVM发展历史
1. 通识
认识UVM的类库和核心机制
学习核心组件和层次构建方式
了解组件之间的通信方式
深入测试场景的构成
寄存器模型应用
💡 UVM的初衷:将验证过程中可以重用和标准化的部分都规定在其方法学的类库中,通过标准化的方式减轻验证人员构建环境的负担
- 对验证环境的共同需求
- 组件的创建和访问
- 环境的结构创建、组件之间的连接和运行
- 不同阶段的顺序安排
- 激励的生成、传递、控制
- 测试的报告机制
- 核心基类
- 工厂类factory
- 事务transaction和序列sequence类
- 结构创建类structure creation
- 环境组件类environment component
- 通信管道类channel
- 信息报告类message report
- 寄存器模型类register model
- 线程同步类thread synchronization
- 事务接口类transaction interface
接下来就会对每个类单独学习
- 软件的一种典型设计模式
工厂的意义
- 更方便的替换验证环境中的实例或注册了的类型(UVM中的覆盖override);带来配置的灵活性
- 被用来替换的对象或类型应该满足注册registration和多态polymorphism
- UVM的验证环境构成分为:环境的层次,通过uvm_component类完成;环境的属性(配置)和数据传输,通过uvm_object完成,component继承于object
- uvm_component和uvm_object是进出工厂的主要模具和生产对象
- 对象由工厂生产,也是利用了工厂生产模具可灵活替代的好处。不需要修改原有验证环境层次和环境包的同时,实现了对环境内部组件类型或对象的覆盖
- 验证环境的不动产包括:generator; stimulator; monitor; agent; checker/reference model; environment; test
- 运用工厂的步骤
- 将类注册到工厂(用UVM宏macro,`uvm_component_utils (comp1))
- 例化前设置覆盖对象和类型
- 对象创建
- factory是独有的,有且只有一个。所有类都注册在一个机构中
class comp1 extends uvm_component;
`uvm_component_utils (comp1)//注册组件;new函数必须只有两个参数
function new (string name=:comp1", uvm_component parent=null);//parent是指上一层,当前实例是谁例化的,谁就是这个实例parent
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;
`uvm_object_utils (obj1)//注册
function new (string name="obj1");//只有一个参数
super.new(name);
$display ($sformatf("%s is created",name));
endfunction: new
endclass
comp1 c1, c2;
obj1 o1,o2;
initial begin
c1 = new ("c1");//任何对象的例化最终都是通过new()函数来实现,sv的方法
o1 = new ("o1");
c2 = comp1::type_id::create ("c2",null);//这个也是例化的写法,factory提供的方法
o2 = obj1::type_id::create("o2"):
end
uvm_coreservice_t类
- 作用:内置了UVM世界核心的组件和方法,包括
- 唯一的uvm_factory组件,用来注册、覆盖、例化
- 全局的report_server组件,用来做消息的统筹和报告
- 全局的tr_database组件,用来记录transaction记录
- get_root()方法,用来返回当前UVM环境的结构顶层对象
- UVM1.2将最重要的机制——必须做统一例化处理的组件——都放置在uvm_coreserice_t中
- 独立于UVM环境之外,没有例化在UVM环境中,只会在仿真开始时被uvm系统例化一次
- 这个核心组件如同一个随时待命的狗,做好服务的准备。理论上可以获取核心服务类中的任何一个对象如uvm_default_factory,继而直接利用factory实现创建和覆盖
uvm_{component, object}类——注册与例化
注册
`uvm_component_utils()用来注册组件类uvm_component
`uvm_object_utils()用来注册核心基类uvm_object
- 宏调用过程中实现类型定义
- typedef uvm_component_registry #(T,
”S
”) type_id
- typedef uvm_component_registry #(T,
uvm_factory::register() 用来注册type_id并且得到实例
- 一旦注册,type_id::create()函数就可以通过uvm_factory::create_component_by_type()实现
- 注册只是相当于名单上有了这个类,例化该类的对象才是真正将抽象的类放置在具体的地方,也就是实体人来报道了
- uvm_default_factory将每个类对应的对象放置到factory的字典dictionary中(不考虑覆盖)
- uvm_default_factory::create_component_by_type() 检查处在该层次路径中需要被例化的对象,是否收到类型覆盖或实例覆盖的影响,将最终类型对应的对象句柄(正确的产品模板)交给工厂
- 然后就可以通过uvm_component_registry::create_component() 完成例化
例化
- 例化时都应该给一个名字string
- full name指的是component所处的完整层次结构
- 每个层次中例化的组件名称要独一无二unique
- 创建两种对象时的语句
comp_type::type_id::creat (string name, uvm_component parent);
组件类型,id是注册到工厂里面的类型,调用create方法
object_type::type_id::creat (string name);
- 创建对象时虽然都要调用create(),但是最终创建出来只有component会表示在uvm层次结构中(有parent);而object不会(没有parent),只能作为configuration或者transaction等用来做传递的配置结构体、抽象数据传输的数据结构体,成为component的成员变量
- 创建对象时需要结合工厂的注册和覆盖机制来决定使用哪一个类型来创建
与工厂有关的方法
- 配合工厂的注册、创建和覆盖
- create()
- create_component()
- get()
- get_type_name()
- set_inst_override()
- set_type_override()
- 每个uvm_componnet的类注册时会定义一个新的uvm_componnet_registry类,就是一个放模板的纸箱,注册时只有被注册类的图纸,还没有真的实例
- 利用工厂创建实例的方法
- create_component_by_name()
- create_component_by_type()
- create_object_by_name()
- create_object_by_type()
- 用两个宏注册类型时,宏内部就将类型T作为类型名Tname=’T’注册到工厂去了,上面任何一种创建对象的方法不会受困于类型和类型名不同的烦恼