1. 概述
多通道数据整形器(MCDF,multi-channel data formatter),可以将上行(uplink)多个通道数据经过内部的FIFO,最终以数据包(data packet)的形式送出。
2. reg_env
- 对于寄存器模块的验证环境reg_env,包括
- reg_master_agent,提供寄存器接口驱动信号
- reg_slave_agent,提供寄存器接口反馈信号
- scoreblard,分别从reg_master_agent内的monitor和reg_slave_agent内的monitor获取监测数据,并进行数据对比
3. chnl_env
- 数据通道从端的验证环境chnl_env的组件包括:
- chnl_master_agent,提供上行的激励数据
- chnl_slave_agent,提供用来模拟arbiter仲裁信号,并且接收流出数据
- reg_cfg_agent,提供用来模拟寄存器的配置信号,并且接收内置FIFO的余量信号
- scoreboard,分别从chnl_master_agent、chnl_slave_agent和reg_cfg_agent的monitor接收监测数据,并且对channel的流入流出数据进行对比
4. arb_env
- 仲裁器的验证环境arb_env的组件包括:
- 模拟channel输出接口的arbiter_master_agent的三个实例,用来对arbiter提供并行数据输入,同时对arbiter反馈的仲裁信号做出相应
- arbiter_slave_aent,用来接收arbiter的输出数据,模拟formatter的行为,对arbiter输出信号做出相应
- reg_cfg_agent,提供用来模拟寄存器的配置信号,对三个channel数据源分别作出不同的优先级配置
- scoreboard,从三个arbiter_master_agent、arbiter_slave_agent和reg_cfg_agent中的monitor获取监测数据,对arbiter的仲裁机制做出预判,并且将输入输出数据按照预测的优先级做出对比
5. fmt_env
- 整形器的验证环境fmt_env的组件包括:
- fmt_master_agent,用来模拟arbiter的输出数据
- fmt_slave_agent,用来模拟MCDF的下行数据接收端
- ref_cfg_agent,用来模拟寄存器的配置信号,用来指定输出数据包的长度
- scoreboard,从fmt_master_agent、fmt_slave_agemt和reg_cfg_agemt的monitor获取监测数据,通过数据包长度来预测输出的数据包,与formatter输出的数据包进行对比
6. 环境集成方案一
- 复用模块验证环境的组件,reg_master_agent、chnl_master_agent、fmt_slave_agent
- scoreboard提供了一套完整的数据通路覆盖方案,即从各个agent的monitor数据监测端口将数据收集起来,同时建立MCDF的参考模型,预测输出数据包,最终进行数据比对
- virtual sequencer控制如何发送激励,协调作用
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); // 创建5个agent
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; // vsqr与5个agent中的sqr句柄连接
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); // TLM通信建立连接
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
7. 环境集成方案二
- 方案二复用了模块环境xxx.env,直观看上去组件很多
- 只需要将各个子模块环境中的agent配置(build阶段)为不同模式(passive或active),减少顶层环境的额外成本
- 不需要实现新的scoreboard
- 两个方案都需要新实现virtual sequencer和virtual sequence,用于生成顶层的测试序列
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; // vsqr与5个agent中的sqr句柄连接
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
8. 对比总结 UVM带来的复用环境的优势
- 各个模块的验证环境是独立封装的,对外不需要保留数据端口,因此便于环境的进一步集成复用
- 由于UVM自身的phase机制,在顶层协调各个子环境时,无需考虑由于子环境之间的例化顺序而导致的对象句柄引用悬空的问题
- 由于子环境的测试序列是相对独立的,这使得顶层在复用子环境测试序列而构成virtual sequence时,不需要其他额外的迁移成本
- UVM提供config_db配置方式,使得整体环境的结构和运行模式都可以从树状的config对象中获取,这也使得顶层环境可以在不同uvm_test进行集中管理配置