基于UVM搭验证环境
基于UVM搭验证环境基本思路:
首先,我们搭建环境时一般都有一个目标的DUT。此时,我们可以结合所要验证的的模块、是否需要VIP、验证侧重点等在典型的UVM验证环境的基础上做适当调整后形成一个大体的环境架构。比如,需要一个ahb_vip_agent、系统级还是模块级的DUT等等。这样,整个验证环境中需要几个in_agent、是否需要out_agent、reference model是否需要自己写就比较清楚了。基于这些考虑,我们的环境架构基本上就定下来了。
其次,当整个环境的架构确定好了之后,接下来就是具体的编写环境组件的过程了。这个是整个环境搭建最重要和工作量最大的部分。有的喜欢自上而下地先写顶层,env再agent,driver,transaction来编写各个组件;有的习惯自下而上地先写好每个driver,monitor再在agent或env中做组合连接。我的经验是,在搭建环境的过程中,认知就是一个从框架到编码的过程,所以自上而下的方式更符合这样一个认知的过程。另外,在真正工作中,我还是觉得我们搭建环境的第一步不要想着一次性把环境中所有的组件都写完,而是先写完除scoreboard和reference model之外的所有规划组件。至于testcase,可以先写好冒烟case(当然可能包括冒烟case需要的sequence)。这样做的目的是我们可以在最短的时间里调试环境并能够正常冒烟。之后再根据项目进度逐步添加reference model,scoreboard,sequence和case等,并不断完善。
基于UVM搭建验证环境的过程:
①编写uvm_env。首先根据确定的环境架构,编写env将整个环境的结构关系确定下来。
②如果环境中要用到vip,可以在env中把vip包进来。
③环境中可能会包含多个agent。其实agent可以理解为一个单一的env。所以还是从agent自顶向下的去编写,agent→interface→sequencer、sequence→driver→moitor。
④在编写agent的driver过程中可能需要同步进行transaction的编写。这样可以不断地调整transaction中的配置变量。
⑤编写top.sv。完成env和agent之后,环境的interface基本也确定下来了。这个时候可以编写顶层信号连接。
⑥编写base_test.sv。这个过程中可以同步编写顶层的transaction以及顶层的一些sequence和sequencer。
⑦待上述编写完成后,开始编写环境和代码的filelist以及仿真脚本。调试冒烟case。
以上7个小点是一个基本的环境搭建步骤。这个环境可以完成待测代码的冒烟测试。之后的工作,就是在这个环境的基础上补充reference model和scoreboard的功能,以及根据验证计划不断补充激励并完成验证工作。
《uvm实战》温习小记:
set与get函数的参数:
config_db机制用于uvm验证平台间传递参数(如int,virtual interface),set与get通常是成对出现的,set函数是寄信,get函数是收信,通常习惯在最顶层处(tb_top)处set,使用方式如下:
uvm_config_db# (int) : : set (this, "env.i_agt.drv" , "pre_num" , 100);
其中第一个参数和第二个参数组合起来组成寄信的目标路径,因此上面也可以改成
uvm_config_db# (int) : : set (this.env, "i_agt.drv" , "pre_num" , 100);(一般不用)
与此路径符合的才能收信,其中第一个参数必须是uvm_component实例的指针,第二个参数是相对于实例的路径。第三个参数表示一个记号,用于说明这个值是传给目标中的哪个成员的,第四个参数是要设置的值。
需要注意的是如果在顶层tb_top中set,用法为
uvm_config_db# (int) : : set (null, "uvm_test_top.env.i_agt.drv" , "pre_num" , 100);
set函数原型:
static function void set(
uvm_component context, // 上下文(作用域)
string inst_name, // 目标实例的路径(支持通配符)
string field_name, // 配置项的名称(字符串)
T value // 要设置的配置值(任意类型)
);
context
作用:定义配置的作用域(通常是一个组件的指针)。
规则:
如果
context
设置为null
,配置将全局可见。如果
context
设置为某个组件(如this
),配置的作用域将限定在该组件的层次结构下。子组件可以通过向上查找父组件的作用域来访问配置。
inst_name
作用:指定目标实例的路径(支持通配符
*
或.*
)。示例:
"uvm_test_top.env.agent"
: 精确匹配路径。
"uvm_test_top.env.*"
: 匹配env
下所有组件。
"*.agent"
: 匹配所有名为agent
的实例。
field_name
作用:配置项的唯一标识符(字符串),需与
get()
中的名称一致。示例:
"vif"
,"cfg"
,"num_packets"
。
value
作用:要传递的值,可以是任意类型(如接口、对象、整数等)。
示例:传递虚拟接口、配置对象、字符串等。
收信一般在组件中的build_phase收信,以driver为例,使用方式如下:
uvm_config_db# (int) : : get (this, "" , "pre_num" , p_num);
其中第一个参数和第二个参数用来组成收信地址,第一个也必须是uvm_component实例的指针,第二个参数则是相对于此实例的路径。一般的,如果第一个参数是this,第二个参数可以是一个空的字符串,第三个参数就是set中的参数,必须严格对应,第四个参数则是该实例中要设置的变量。
get函数原型:
static function bit get(
uvm_component context, // 上下文(作用域)
string inst_name, // 当前实例的路径
string field_name, // 配置项的名称
inout T value // 接收配置值的变量
);
context
作用:与
set()
中的context
对应,定义查找配置的作用域。规则:
通常设置为
this
(当前组件),UVM 会从当前组件向上遍历父组件的作用域查找配置。如果设置为
null
,则从全局作用域查找。
inst_name
作用:当前组件的完整路径名,通常通过
get_full_name()
获取。自动获取:在组件内部使用时,可以直接用
uvm_root::get().get_full_name()
或this.get_full_name()
。
field_name
作用:与
set()
中的field_name
一致,用于匹配配置项。
value
作用:接收配置值的变量,类型必须与
set()
中传递的类型一致。注意:如果未找到配置,
get()
返回0
,且value
保持不变。
关键使用场景
1. 传递虚拟接口(Virtual Interface)
// 在顶层模块中设置接口
initial begin
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env.agent", "vif", apb_if);
end// 在 Agent 中获取接口
class my_agent extends uvm_agent;
virtual apb_if vif;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(virtual apb_if)::get(this, "", "vif", vif)) begin
`uvm_fatal("CFGERR", "Failed to get vif!")
end
endfunction
endclass
2. 传递配置对象
// 在测试用例中设置配置对象
class my_test extends uvm_test;
my_config cfg;
function void build_phase(uvm_phase phase);
cfg = my_config::type_id::create("cfg");
cfg.mode = FAST_MODE;
uvm_config_db#(my_config)::set(this, "env.agent", "cfg", cfg);
endfunction
endclass// 在 Agent 中获取配置对象
class my_agent extends uvm_agent;
my_config cfg;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(my_config)::get(this, "", "cfg", cfg)) begin
`uvm_fatal("CFGERR", "Failed to get cfg!")
end
endfunction
endclass
注意事项
-
作用域匹配
-
set()
和get()
的context
和inst_name
必须匹配,否则无法获取配置。 -
例如:
set(this, "env.agent", ...)
和get(this, "env.agent", ...)
。
-
-
通配符的使用
-
使用
*
或.*
可以简化路径匹配,但要避免过度使用导致配置冲突。
-
-
类型一致性
-
set()
和get()
的模板参数(如uvm_config_db#(int)
)必须完全一致。
-
-
时序问题
-
set()
应在get()
之前执行(通常在build_phase
中设置)。
-