目录
1 UVM结构回顾
uvm_top
uvm_top是uvm_root类的唯一实例,是uvm世界的“一”。它由uvm创建和管理,所在的域是uvm_pakg。
uvm_top是所有test组件的顶层
uvm_top提供一系列方法来控制仿真,例如phase机制、objection防止仿真退出等。
uvm_test
“test”类是用户自定义类结构的顶层,所有的test都应继承于uvm_test,否则uvm_top将不予承认。
test中可以包含:环境配置config_db、工厂覆盖机制、测试序列、验证环境。其中验证环境是test中的不动产,其余可以根据需要进行相应配置。
构建环境的主要组件
主要有三大类共同组成验证环境:uvm_component uvm_env uvm_test
uvm_component:
本身是一个虚类,所有的验证组件均继承于uvm_component,可以提供统一的方式管理层次结构和组件方法。对于组件的构建函数function new(string name,uvm_component parent),它是有两个参数,其中uvm_component parent用来指示实例的上一级句柄,通常用“this”来指代,即例化在当前层次
uvm_env:继承于uvm_component,为验证环境提供一个容器
uvm_test:继承于uvm_component ,对uvm_env进行额外的配置及挂载激励。
2 环境的集成方案
方案介绍
方案一:直接复用底层验证模块环境中的组件,但同时需新建一个scoreboard。
方案二:直接复用底层模块的验证环境,只需将各个子模块的agent配置成相应的active或passive以适应顶层验证环境要求。如有必要可新建一个简单的scorebord.。
方案一验证结构及实例说明:
class mcdf_env1 extends uvm_env;
`uvm_component_utils(mcdf_env1)
reg_master_agent reg_mst;
chnl_master_agent chnl_mst1;
chnl_master_agent chnl_mst2;
chnl_master_agent chnl_mst3;
fmt_slave_agent fmt_slv;
mcdf_virtual_sequencer virt_sqr;
mcdf_scoreboard sb;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
reg_mst = reg_master_agent::type_id::create("reg_mst", this);
chnl_mst1 = chnl_master_agent::type_id::create("chnl_mst1", this);
chnl_mst2 = chnl_master_agent::type_id::create("chnl_mst2", this);
chnl_mst3 = chnl_master_agent::type_id::create("chnl_mst3", this);
fmt_slv = fmt_slave_agent::type_id::create("fmt_slv", this);
virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
sb = mcdf_scoreboard::type_id::create("sb", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//virtual sequencer connect
virt_sqr.reg_sqr = reg_mst.sequencer;
virt_sqr.chnl_sqr1 = chnl_mst1.sequencer;
virt_sqr.chnl_sqr2 = chnl_mst2.sequencer;
virt_sqr.chnl_sqr3 = chnl_mst3.sequencer;
virt_sqr.fmt_sqr = fmt_slv.sequencer;
//monitor transactions to scoreboard
reg_mst.monitor.ap.connect(sb.reg_export);
chnl_mst1.monitor.ap.connect(sb.chnl1_export);
chnl_mst2.monitor.ap.connect(sb.chnl2_export);
chnl_mst3.monitor.ap.connect(sb.chnl3_export);
fmt_slv.monitor.ap.connect(sb.fmt_export);
endfunction
endclass
方案二验证结构及实例;
class mcdf_env1 extends uvm_env;
`uvm_component_utils(mcdf_env1)
reg_env reg_e;
chnl_env chnl_e1;
chnl_env chnl_e2;
chnl_env chnl_e3;
fmt_env fmt_e;
arb_env arb_e;
mcdf_virtual_sequencer virt_sqr;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
//将子环境配置为active或者passive模式
uvm_config_db#(int)::set(this, "reg_e.slave", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e1.slave", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e1.reg_cfg", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e2.slave", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e2.reg_cfg", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e3.slave", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "chnl_e3.reg_cfg", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "arb_e.master1", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "arb_e.master2", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "arb_e.master3", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "arb_e.slave", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "arb_e.reg_cfg", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "fmt_e.master", "is_active", UVM_PASSIVE);
uvm_config_db#(int)::set(this, "fmt_e.reg_cfg", "is_active", UVM_PASSIVE);
//创建子环境
reg_e = reg_env::type_id::create("reg_e", this);
chnl_e1 = chnl_env::type_id::create("chnl_e1", this);
chnl_e2 = chnl_env::type_id::create("chnl_e2", this);
chnl_e3 = chnl_env::type_id::create("chnl_e3", this);
virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//virtual sequencer connection
virt_sqr.reg_sqr = reg_e.master.sequencer;
virt_sqr.chnl_sqr1 = chnl_e1.master.sequencer;
virt_sqr.chnl_sqr2 = chnl_e2.master.sequencer;
virt_sqr.chnl_sqr3 = chnl_e3.master.sequencer;
virt_sqr.fmt_sqr = fmt_e.slave.sequencer;
endfunction
endclass
注意事项:build_phase中的config配置需在例化之前完成。
两种方案对比:
相同点:顶层都需要新建virtual sequencer和virtualsequence用来生成顶层的测试序列。
不同点:方案一需要新建一个scorebord,方案二需复用全部之前的验证环境。若设计没那么复杂,重新设计顶层scorebord可控,要是环境非常复杂,那么复用scorebord将会省时省力。
总结:相比于sv验证环境,uvm环境复用的优势
1 各个模块的验证环境是独立封装的,对外不需要保留数据端口,因此便于环境的进一步集成复用。(使用tlm通信,不存在mailbox句柄为空的现象)
2 由于UVM自身的phase机制,在顶层协调各个子环境时,无需考虑由于子环境之间的例化顺序而导致的对象句柄引用悬空的问题。
3 由于子环境的测试序列是相对独立的,这使得顶层在复用子环境测试序列而构成virtual sequence时,不需要其它额外的迁移成本。
4 UVM提供的config_db配置方式,使得整体环境的结构和运行模式都可以从树状的config对象中获取,这也使得顶层环境可以在不同uvm_test进行集中管理配置。(可在组件例化之前先配置)
3 构建环境的内径
构建环境四要素:单元组件的自闭性 回归创建 通信端口连接 顶层配置
单元组件的自闭性
自闭性指的是单元组件(例如uvm_agent
或者uvm_env
)自身可以成为独立行为、不依赖于其它并行的组件;这种自闭性为以后环境的复用提供了良好的基础;各个子环境也独立于集成的顶层环境,互相不需要额外的通信连接。(在sv中确不能单独例化driver因为里面含有mailbox的空句柄)
回归创建
环境的框架主要依靠回归创建,通过build_phase
这种结构化执行顺序可以保证父组件必先于子组件创建,而创建过程还包括:默认值、结构配置、模式配置,自顶向下顺序执行。
通信端口连接
在完成整个环境的创建后,各个组件会通过通信端口进行数据通信
顶层配置
正是由于单元组建的自闭性,uvm结构不建议通过引用子环境句柄来索引深层次变量进行配置(降低粘性)。更好的方式是通过配置化对象,绑定在顶层环境中,子环境的各个组件从结构化的配置对象中获取相关配置参数。
顶层配置对象可以在子环境没有例化时就将其配置到将来会创建的子环境当中,无需考虑顶层配置对象会先于子环境生成,这也为UVM验证结构提供了安全的配置方式,但应注意的是:
使用配置时,所有配置尽量置于组件创建之前,保证配置生效;配置的作用域只关注当前层次;配置 的对象结构应尽量独立;config_db特性使高层配置将覆盖底层配置。
实例:验证环境中元素的分类