在由systemverilog搭建的验证环境中,我们可以使用系统函数$value$plusargs来获取仿真时的仿真参数。而在基于UVM的验证环境中,我们可以使用另一种方式来获取仿真参数:uvm_cmdline_processor。
uvm_cmdline_processor本质上是一个class,它的继承关系如下:
在这个类中,实现了以下两大类的功能(本文只关注第一类的功能):
实际上,在uvm_cmdline_processor这个类里面定义了一些string队列,用于存储相关的仿真参数,这些队列如下:
protected string m_argv[$];
protected string m_plus_argv[$];
protected string m_uvm_argv[$];
虽然知道了在这些队列中存储了相关的仿真参数,但是由于这些队列都是protected的,我们只能通过对应的函数来进行访问,这些函数的原型如下:
function void get_args (output string args[$]);
function void get_plusargs (output string args[$]);
function void get_uvm_args (output string args[$]);
另一个令人比较感兴趣的问题是,这些队列在什么时候被初始化。阅读对应的源码,可以看到这件事情发生在class的构造函数中:
function new(string name = "");
string s;
string sub;
super.new(name);
do begin
s = uvm_dpi_get_next_arg();
if(s!="") begin
m_argv.push_back(s);
if(s[0] == "+") begin
m_plus_argv.push_back(s);
end
if(s.len() >= 4 && (s[0]=="-" || s[0]=="+")) begin
sub = s.substr(1,3);
sub = sub.toupper();
if(sub == "UVM")
m_uvm_argv.push_back(s);
end
end
end while(s!="");
细心的你可能已经发现了,对仿真参数的处理采用的是dpi+字符串的手段,而不是调用系统函数$value$plusargs。那么问题又来了,既然是在构造函数中完成队列初始化的,那么我们是不是还需要构造一个uvm_cmdline_processor类的实例?其实这一步也是不需要的,因为在源码中,已经帮我们做好了。
static function uvm_cmdline_processor get_inst();
if(m_inst == null)
m_inst = new("uvm_cmdline_proc");
return m_inst;
endfunction
const uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst();
因此,在实际的验证环境中,我们的使用可以非常简单:
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg::*;
program testcase();
string cmdline_argv[$];
string cmdline_plus_argv[$];
string cmdline_uvm_argv[$];
initial begin
$display("*************************************************************");
uvm_cmdline_proc.get_args(cmdline_argv);
uvm_cmdline_proc.get_plusargs(cmdline_plus_argv);
uvm_cmdline_proc.get_uvm_args(cmdline_uvm_argv);
foreach(cmdline_argv[i]) $display("cmdline_argv[%0d] =%s", i, cmdline_argv [i]);
foreach(cmdline_plus_argv[i]) $display("cmdline_plus_argv[%0d]=%s", i, cmdline_plus_argv[i]);
foreach(cmdline_uvm_argv[i]) $display("cmdline_uvm_argv[%0d] =%s", i, cmdline_uvm_argv [i]);
$display("*************************************************************");
$finish();
end
endprogram
假如Makefile中的仿真参数如下:
./simv -l run_ver.log +plus_argv_test1 -plus_argv_test2 +UVM_argv_test1 -uvm_argv_test2=2
那么仿真的结果如下:
*************************************************************
cmdline_argv[0] =./simv
cmdline_argv[1] =-l
cmdline_argv[2] =run_ver.log
cmdline_argv[3] =+plus_argv_test1
cmdline_argv[4] =-plus_argv_test2
cmdline_argv[5] =+UVM_argv_test1
cmdline_argv[6] =-uvm_argv_test2=2
cmdline_plus_argv[0]=+plus_argv_test1
cmdline_plus_argv[1]=+UVM_argv_test1
cmdline_uvm_argv[0] =+UVM_argv_test1
cmdline_uvm_argv[1] =-uvm_argv_test2=2
*************************************************************
事实上,uvm还提供了更丰富的函数库:
function int get_arg_matches (string match, ref string args[$]);
//| void'(uvm_cmdline_proc.get_arg_matches("+foo",myargs)); //matches +foo, +foobar
//| //doesn't match +barfoo
//| void'(uvm_cmdline_proc.get_arg_matches("/foo/",myargs)); //matches +foo, +foobar,
//| //foo.sv, barfoo, etc.
//| void'(uvm_cmdline_proc.get_arg_matches("/^foo.*\.sv",myargs)); //matches foo.sv
//| //and foo123.sv,
//| //not barfoo.sv.
get_arg_matches允许我们搜索并返回满足条件的仿真参数。match是搜索条件,args[$]是满足搜索条件的仿真参数,function返回的int值则是满足搜索条件的仿真参数个数。由于使用了dpi接口,match甚至于还支持正则表达式。
function int get_arg_value (string match, ref string value);
function int get_arg_values (string match, ref string values[$]);
// For example if '+foo=1,yes,on +foo=5,no,off' was provided on the command
// line and the following code was executed:
//| void'(uvm_cmdline_proc.get_arg_values("+foo=",foo_values));
// The foo_values queue would contain two entries. These entries are shown
// here:
// 0 - "1,yes,on"
// 1 - "5,no,off"
get_arg_value和get_arg_values函数允许我们搜索以match字符串为开头的仿真参数。两个函数的区别在于一个只返回搜索到的第一个值,一个返回搜索到的所有满足条件的值。
function string get_tool_name ();
function string get_tool_version ();
get_tool_name和get_tool_version函数允许我们获取仿真工具的名称和版本,实际上,这部分的实现已经通过dpi交还给了EDA vender。