这篇文章将解释UVM配置对象,因为之前的文章并没有太多的介绍。 jelly-bean验证平台使用jelly_bean_agent_config和jelly_bean_env_config两种配置对象。 前者配置jelly_bean_agent,后者配置jelly_bean_env。 下图显示了验证平台和配置相关类的类图。
Verification Platform
Class Diagram of the Configuration Classes
Agent Configuration
jelly_bean_agent_config类配置jelly_bean_agent。这个类有两个开关; active和has_jb_fc_sub(第4和5行)。active控制代理是处于主动模式还是处于被动模式。在主动模式下,将创建一个sequencer(jelly_bean_sequencer)和一个driver(jelly_bean_driver)。在被动模式下,不会创建任何sequencer或driver。类似地,has_jb_fc_sub开关控制代理是否实例化功能覆盖采集器(jelly_bean_fc_subscriber)。根据开关的值,代理将被组织为下图所示的四种可能配置之一。 jelly_bean_agent_config类也具有jelly_bean_if(第7行)的句柄。
class jelly_bean_agent_config extends uvm_object;
`uvm_object_utils( jelly_bean_agent_config )
uvm_active_passive_enum active = UVM_ACTIVE;
bit has_jb_fc_sub = 1; // switch to instantiate a functional coverage subscriber
virtual jelly_bean_if jb_if;
function new( string name = "" );
super.new( name );
endfunction: new
endclass: jelly_bean_agent_config
Four Possible Agent Configurations
Environment Configuration
类似于jelly_bean_agent_config,jelly_bean_env_config配置jelly_bean_env。该类有四个开关来定义环境的结构(第4至7行)。它还有两个处理jelly_bean_agent_config;每个代理人一个句柄(第9和10行)。
class jelly_bean_env_config extends uvm_object;
`uvm_object_utils( jelly_bean_env_config )
bit has_jb_agent1 = 1; // switch to instantiate an agent #1
bit has_jb_agent2 = 1; // switch to instantiate an agent #2
bit has_jb_sb1 = 1; // switch to instantiate a scoreboard #1
bit has_jb_sb2 = 1; // switch to instantiate a scoreboard #2
jelly_bean_agent_config jb_agent_cfg1;
jelly_bean_agent_config jb_agent_cfg2;
function new( string name = "" );
super.new( name );
endfunction: new
endclass: jelly_bean_env_config
Top Module
顶级Verilog模块实例化两个jelly_bean_ifs(第6行和第7行)并将它们存储在配置数据库中(第17行至第20行)。 cntxt和inst_name提供正在存储的虚拟接口的范围信息。由于顶层模块不是uvm_component,所以null被用作cntxt。 uvm_test_top是由uvm_root类的run_test()任务实例化的顶层uvm_component的名称。
module top;
import uvm_pkg::*;
reg clk;
jelly_bean_if jb_if1( clk );
jelly_bean_if jb_if2( clk );
jelly_bean_subsystem dut( jb_if1, jb_if2 );
initial begin
clk = 0;
#5ns ;
forever #5ns clk = ! clk;
end
initial begin
uvm_config_db#( virtual jelly_bean_if )::set
( .cntxt( null ), .inst_name( "uvm_test_top" ), .field_name( "jb_if1" ), .value( jb_if1 ) );
uvm_config_db#( virtual jelly_bean_if )::set
( .cntxt( null ), .inst_name( "uvm_test_top" ), .field_name( "jb_if2" ), .value( jb_if2 ) );
run_test();
end
endmodule: top
Base Test
基本测试按如下方式构建配置对象:
基础测试为验证环境创建一个配置对象(jb_env_cfg),并为jelly-bean代理(第16至18行)创建两个配置对象(jb_agent_cfg1和jb_agent_cfg2)。
我们在顶层模块中创建的jelly_bean_ifs从配置数据库中检索。然后将每个检索到的接口分配给相应的代理配置(第20至27行)。
代理配置分配给jb_env_cfg(第29和30行)。
jb_env_cfg存储在配置数据库中,以便验证环境稍后可以从数据库中获取其配置(第32行和第33行)。
class jelly_bean_base_test extends uvm_test;
`uvm_component_utils( jelly_bean_base_test )
jelly_bean_env jb_env;
jelly_bean_env_config jb_env_cfg;
jelly_bean_agent_config jb_agent_cfg1;
jelly_bean_agent_config jb_agent_cfg2;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
jb_env_cfg = jelly_bean_env_config ::type_id::create( "jb_env_cfg" );
jb_agent_cfg1 = jelly_bean_agent_config::type_id::create( "jb_agent_cfg1" );
jb_agent_cfg2 = jelly_bean_agent_config::type_id::create( "jb_agent_cfg2" );
if ( ! uvm_config_db#( virtual jelly_bean_if )::get
( .cntxt( this ), .inst_name( "" ), .field_name( "jb_if1" ), .value( jb_agent_cfg1.jb_if ) ) ) begin
`uvm_error( "jelly_bean_test", "jb_if1 not found" )
end
if ( ! uvm_config_db#( virtual jelly_bean_if )::get
( .cntxt( this ), .inst_name( "" ), .field_name( "jb_if2" ), .value( jb_agent_cfg2.jb_if ) ) ) begin
`uvm_error( "jelly_bean_test", "jb_if2 not found" )
end
jb_env_cfg.jb_agent_cfg1 = jb_agent_cfg1;
jb_env_cfg.jb_agent_cfg2 = jb_agent_cfg2;
uvm_config_db#( jelly_bean_env_config )::set
( .cntxt( this ), .inst_name( "*" ), .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) );
jb_env = jelly_bean_env::type_id::create( .name( "jb_env" ), .parent( this ) );
endfunction: build_phase
endclass: jelly_bean_base_test
Environment
验证环境使用其配置对象构建自身,如下所示:
环境类从配置数据库(第17到20行)获取其配置对象(jb_env_cfg)。
如果配置对象指示要创建的代理#1,则环境会创建它并将其配置(jb_agent_cfg1)存储到配置数据库(第23至25行)。
如果配置对象指示创建计分板,则会创建一个计分板(第27至29行)。
如果两个对象都被实例化(代码行47和48),代理的分析端口和计分板的export都是连接的。
class jelly_bean_env extends uvm_env;
`uvm_component_utils( jelly_bean_env )
jelly_bean_env_config jb_env_cfg;
jelly_bean_agent jb_agent1;
jelly_bean_agent jb_agent2;
jelly_bean_scoreboard jb_sb1;
jelly_bean_scoreboard jb_sb2;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
if ( ! uvm_config_db#( jelly_bean_env_config )::get
( .cntxt( this ), .inst_name( "" ), .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) ) ) begin
`uvm_error( "jelly_bean_env", "jb_env_cfg not found" )
end
if ( jb_env_cfg.has_jb_agent1 ) begin
uvm_config_db#( jelly_bean_agent_config )::set
( .cntxt( this ), .inst_name( "jb_agent1*" ), .field_name( "jb_agent_cfg" ), .value( jb_env_cfg.jb_agent_cfg1 ) );
jb_agent1 = jelly_bean_agent::type_id::create( .name( "jb_agent1" ), .parent( this ) );
if ( jb_env_cfg.has_jb_sb1 ) begin
jb_sb1 = jelly_bean_scoreboard::type_id::create( .name( "jb_sb1" ), .parent( this ) );
end
end
if ( jb_env_cfg.has_jb_agent2 ) begin
uvm_config_db#( jelly_bean_agent_config )::set
( .cntxt( this ), .inst_name( "jb_agent2*" ), .field_name( "jb_agent_cfg" ), .value( jb_env_cfg.jb_agent_cfg2 ) );
jb_agent2 = jelly_bean_agent::type_id::create( .name( "jb_agent2" ), .parent( this ) );
if ( jb_env_cfg.has_jb_sb2 ) begin
jb_sb2 = jelly_bean_scoreboard::type_id::create( .name( "jb_sb2" ), .parent( this ) );
end
end
endfunction: build_phase
function void connect_phase( uvm_phase phase );
super.connect_phase( phase );
if ( jb_env_cfg.has_jb_agent1 && jb_env_cfg.has_jb_sb1 ) jb_agent1.jb_ap.connect( jb_sb1.jb_analysis_export );
if ( jb_env_cfg.has_jb_agent2 && jb_env_cfg.has_jb_sb2 ) jb_agent2.jb_ap.connect( jb_sb2.jb_analysis_export );
endfunction: connect_phase
endclass: jelly_bean_env
Agent
代理使用其配置对象构建自己,如下所示:
代理类从配置数据库(第19行到第22行)获取其配置对象(jb_agent_cfg)。
如果配置对象指示代理处于活动状态,则代理会创建一个sequencer和一个driver(第24至27行)。
如果配置对象指示这样做,则创建功能覆盖用户(第29到31行)。
如果代理处于活动状态,则连接driver的端口和sequencer的export。driver的虚拟接口也已连接(第42至45行)。
如果功能覆盖用户存在(第47至49行),则代理的分析端口和功能覆盖用户的分析export被连接。
class jelly_bean_agent extends uvm_agent;
`uvm_component_utils( jelly_bean_agent )
jelly_bean_agent_config jb_agent_cfg;
jelly_bean_sequencer jb_seqr;
jelly_bean_driver jb_drvr;
jelly_bean_monitor jb_mon;
jelly_bean_fc_subscriber jb_fc_sub;
uvm_analysis_port#( jelly_bean_transaction ) jb_ap;
function new( string name, uvm_component parent );
super.new( name, parent );
endfunction: new
function void build_phase( uvm_phase phase );
super.build_phase( phase );
if ( ! uvm_config_db#( jelly_bean_agent_config )::get
( .cntxt( this ), .inst_name( "" ), .field_name( "jb_agent_cfg" ), .value( jb_agent_cfg ) ) ) begin
`uvm_error( "jelly_bean_agent", "jb_agent_cfg not found" )
end
if ( jb_agent_cfg.active == UVM_ACTIVE ) begin
jb_seqr = jelly_bean_sequencer::type_id::create( .name( "jb_seqr" ), .parent( this ) );
jb_drvr = jelly_bean_driver ::type_id::create( .name( "jb_drvr" ), .parent( this ) );
end
if ( jb_agent_cfg.has_jb_fc_sub ) begin
jb_fc_sub = jelly_bean_fc_subscriber::type_id::create( .name( "jb_fc_sub" ), .parent( this ) );
end
jb_mon = jelly_bean_monitor::type_id::create( .name( "jb_mon" ), .parent( this ) );
endfunction: build_phase
function void connect_phase( uvm_phase phase );
super.connect_phase( phase );
jb_mon.jb_if = jb_agent_cfg.jb_if;
jb_ap = jb_mon.jb_ap;
if ( jb_agent_cfg.active == UVM_ACTIVE ) begin
jb_drvr.seq_item_port.connect( jb_seqr.seq_item_export );
jb_drvr.jb_if = jb_agent_cfg.jb_if;
end
if ( jb_agent_cfg.has_jb_fc_sub ) begin
jb_ap.connect( jb_fc_sub.analysis_export );
end
endfunction: connect_phase
endclass: jelly_bean_agent
Sequence Diagram
以下序列图总结了上述配置过程。
Sequence Diagram of the Build Phases
我希望本教程能帮助你理解UVM的配置过程。