在IC验证(VCS仿真)中,$test$plusargs 和 $value$plusargs 是两个非常实用的系统函数。它们允许你在不重新编译代码的情况下,通过仿真运行命令行(Runtime)直接向环境传递参数,从而控制测试行为。
1. testplusargs(标志位检测)
这个函数用于检查命令行中是否出现了某个特定的字符串(前缀匹配)。它通常作为一种"开关"来使用。
-
语法:
if ($test$plusargs("STRING")) ... -
特点: 只判断"是否存在",不解析具体数值。
-
匹配规则: 它匹配的是前缀。例如,如果命令行有
+HELLO_WORLD,那么$test$plusargs("HELLO")也会返回真。
cpp
initial begin
if ($test$plusargs("DEBUG_MODE")) begin
$display("Run-time info: Debug mode is ON");
// 开启额外的打印或波形
end
end
命令行输入: ./simv +DEBUG_MODE
2. valueplusargs(数值传递)
这个函数不仅检查字符串是否存在,还会将字符串中跟随的值转换并存储到变量中。
-
语法:
$value$plusargs("STRING=%format", variable) -
格式符 (%format):
-
%d: 十进制 (Decimal) -
%h: 十六进制 (Hex) -
%s: 字符串 (String) -
%b: 二进制 (Binary) -
%f: 浮点数 (Real)
-
cpp
int max_packet_count;
string test_name;
initial begin
// 获取整数值
if ($value$plusargs("MAX_PKTS=%d", max_packet_count)) begin
$display("Setting max packets to %0d", max_packet_count);
end
// 获取字符串
if ($value$plusargs("TEST_CASE=%s", test_name)) begin
$display("Running test: %s", test_name);
end
end
命令行输入: ./simv +MAX_PKTS=500 +TEST_CASE=my_test_v1
3. 两者的对比总结
| 特性 | testplusargs | valueplusargs |
|---|---|---|
| 主要用途 | 充当开关 (Enable/Disable) | 传递具体配置值 (Value) |
| 返回值 | 返回布尔值(是否存在) | 返回布尔值,并赋值给第二个参数 |
| 参数复杂度 | 仅需指定字符串 | 需要指定格式符(如 %d, %s) |
| 典型场景 | 开启波形、跳过某段初始化 | 设置超时时间、指定测试用例名、配置频率 |
4. 延伸:VCS 中的底层逻辑
在 VCS 仿真运行过程中,当仿真器扫描到命令行字符串时:
-
它会维护一个包含所有
+参数的列表。 -
当代码执行到
$value$plusargs时,仿真器会在这个列表中搜索匹配的字符串。 -
找到匹配项后,根据你提供的格式符(如
%d)进行类型转换,然后赋值给你的变量。
在 VCS(以及大多数 EDA 工具)中,参数前缀使用 + 还是 - 有着本质的区别。简单来说:- 是给仿真器软件看的,+ 是给你写的代码看的。
1. 带 - 的参数:仿真器指令 (Tool Options)
这些参数是 VCS 软件内置的开关,用于控制仿真器的行为、性能或功能。
-
接收者: VCS 引擎(底层 C++/二进制代码)。
-
作用: 开启/关闭仿真器的原生功能(如日志、波形、覆盖率、界面等)。
-
是否需要代码支持: 不需要。无论你代码怎么写,这些参数都有效。
-
常用示例:
-
-gui:启动图形界面。 -
-l sim.log:指定日志文件。 -
-ucli:启用 TCL 交互命令行。 -
-cm line:收集行覆盖率。
-
2. 带 + 的参数:用户自定义参数 (Plusargs)
这些参数通常是用户自定义的,或者是某些**高级库(如 UVM)**预留的接口。
-
接收者: 你在 SystemVerilog 中写的测试平台(Testbench)。
-
作用: 通过
$test$plusargs或$value$plusargs被你的代码读取,从而改变测试逻辑(如修改种子、切换测试用例、配置寄存器地址等)。 -
是否需要代码支持: 需要 。除非你在代码里调用了相关的系统函数去解析它,否则你在命令行输入
+HELLO,仿真器只会直接忽略它。 -
常用示例:
-
+SEED=12345:传递随机种子给代码。 -
+UVM_TESTNAME=my_test:告知 UVM 框架运行哪个 Case(UVM 内部通过$value$plusargs读取)。 -
+DEBUG_MODE:触发代码里的if($test$plusargs(...))块。
-
3. 对比总结表
| 特性 | - 参数 (Minus Options) | + 参数 (Plus Arguments) |
|---|---|---|
| 定义者 | 仿真器厂商 (Synopsys) | 用户或库开发者 (UVM/Methodology) |
| 解析方式 | 仿真器内核自动解析 | 代码中使用 $test$plusargs 等手动解析 |
| 灵活性 | 固定,由工具版本决定 | 无限,随你心情定义 |
| 冲突处理 | 输入错误通常会导致仿真报错退出 | 输入错误(或未匹配)通常被忽略,无影响 |
| 典型用途 | 仿真环境配置(波形、License、性能) | 测试逻辑配置(参数化、用例选择、寄存器值) |
虽然绝大多数情况遵循这个规律,但 VCS 也有极少数自带的参数使用 + 开头,比如 +vcs+lic+wait(等待 License)和 +v2k(支持 Verilog-2000 标准)。这些可以看作是"系统级"的 plusargs。
5. valueplusargs 这是两个系统函数拼起来的吗
不是。 虽然它的名字看起来像是由 $value 和 $plusargs 组合而成的,但它在 SystemVerilog 标准中是一个独立的、完整的一体化系统函数 。两个 $ 并不是代表两个独立函数的拼接,而是为了语义分隔。
1. 拆解命名的含义
我们可以把这个名字看作是三个语义部分的组合:
-
$:代表这是一个系统任务或函数(System Task/Function)。 -
value:代表它的核心功能是提取数值(Value Extraction)。 -
plusargs:代表它作用于命令行中以+号开头的参数(Plus Arguments)。
2.为什么中间多了一个 $?
你可以把这个命名看作是一个**"分层分类"**的结构:
-
第一个
$:它是所有系统函数的标志,相当于在说:"注意,我要调用仿真器内置的功能了。" -
中间的
$:它在这里起到了分隔符 的作用,类似于其他编程语言中的下划线_或点.。
6. +MAX_PKTS=500 在解析的时候怎么知道这个500是数字还是字符串?
这是一个非常经典的问题。答案是:仿真器本身并不知道它是数字还是字符串,它完全取决于你在代码中使用的"格式说明符"以及接收变量的类型。
在解析 +MAX_PKTS=500 时,$value$plusargs 会按照你指定的格式进行强制转换。
1. 它是数字还是字符串,由你决定
你可以用不同的方式去"解读"这同一个参数:
情况 A:把它当作【数字】解析
如果你在代码里写 %d,仿真器就会尝试把 =号 后面的字符转换成十进制整数。
cpp
int pkts;
initial begin
// 仿真器看到 %d,会尝试将 "500" 转换为整数 500
if ($value$plusargs("MAX_PKTS=%d", pkts)) begin
$display("解析为数字: %0d", pkts);
end
end
情况 B:把它当作【字符串】解析
如果你在代码里写 %s,仿真器就会直接把 "500" 这三个字符当作字符串存入变量。
cpp
string s_pkts;
initial begin
// 仿真器看到 %s,会直接取字符串 "500"
if ($value$plusargs("MAX_PKTS=%s", s_pkts)) begin
$display("解析为字符串: %s", s_pkts);
end
end
2. 万一解析失败了怎么办?
解析成功与否遵循以下原则:
-
格式不匹配: 如果你写了
+MAX_PKTS=abc,但代码里用%d尝试解析,解析会失败,$value$plusargs会返回0(假),且目标变量pkts不会被修改。 -
部分匹配: 如果你写了
+MAX_PKTS=500abc,使用%d解析,通常仿真器会解析出500然后停止(具体取决于仿真器实现,建议避免这种写法)。 -
十六进制: 如果你想传递十六进制,命令行写
+ADDR=A0,代码里必须对应使用%h。
3. 底层原理:一切皆字符串
在操作系统的层面, ./simv +MAX_PKTS=500 传入的所有内容最初都是字符串。
$value$plusargs 的作用就像是 C 语言里的 sscanf:
-
它先在命令行参数中寻找匹配
MAX_PKTS=的字符串。 -
找到后,截取剩下的部分(即
"500")。 -
根据你提供的格式符(
%d,%s,%h,%f),把这个字符串"翻译"成目标类型。
总结
-
你想它是数字: 代码用
%d,变量定义为int或bit。 -
你想它是字符串: 代码用
%s,变量定义为string。
经验之谈: 在验证环境(UVM)中,建议始终通过这种方式传递参数,并给变量设置一个默认值 。如果 $value$plusargs 返回 0,就使用默认值,这样即使命令行忘了写参数,仿真也能正常跑下去。