首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你还在用plusargs传递参数吗?来试试这个玩法~

你还在用plusargs传递参数吗?来试试这个玩法~

作者头像
IC验证
发布2020-11-03 14:32:27
1.8K0
发布2020-11-03 14:32:27
举报
文章被收录于专栏:杰瑞IC验证杰瑞IC验证

本文根据真实项目改编,若有雷同,纯属意外。

当我们在创建动态仿真case时,使用命令行参数可以非常方便地控制DUT和TB的行为,比如配置寄存器、控制激励的发送数量、打开或关闭某些scoreboard等。

当面对很多验证组件,并且有很多命令行参数需要传递的时候,如何才能简单地实现给这些组件传递命令行参数呢?

大家首先想到的可能是plusargs。

没错,plusargs的确是一个非常简单易用的机制。对于规模小的项目,完全够用。但是对于像包含了100个agent、涉及多个工程师共同开发的复杂大项目,plusargs的缺陷就暴露出来了。

1

plusargs的缺陷

首先,plusargs使用的位置太随意了,可以在module、class、interface等等任何能使用begin/end块的地方解析命令行参数。这就埋下了彼此影响的坑。看过jerry之前文章“testplusargs(),valueplusargs()怎么用?有什么坑?”的朋友们还记得,plusargs不仅仅认为“张三”和“张三”同名,连“张三”和“张三丰”也算同名!使用的时候,稍有不慎,可能会因为同名误伤了其他组件。

其次,plusargs使用的时候,命令行参数的格式必须跟解析的格式一样,否则会传递失败,甚至传递错误的值。比如:按照16进制解析的参数,如果按10进制传递,就会传递错误的值。即使传递16进制,到底是按照+data=‘hff00传递,还是按照+data=32’hff00传递,又或者按照+data=ff00传递,也需要提前约定并统一风格。这在大型项目里,直接增加了沟通成本。

另外,plusargs不支持数组和枚举类型的数据。用户必须自己编写额外代码进行解析。

2

uvm命令行参数简介

uvm定义了一套自己的命令行参数规则,可以非常方便地从命令行传递常用类型数据到tb里,完美地解决了上面提到的几个缺陷。下面逐一举例说明。

2.1 传递int类型参数

图1 代码片段1

如图1代码片段所示,32和33行定义了40-bit变量data和int变量data_vld,为了让uvm命令行参数可以传递值给它们,需要添加36和37行的声明。

这里需要注意下,uvm_field_int只是声明这个变量按照整数数据类型解析(而不是real浮点数、string字符串、enum枚举或者数组等类型), 大家不用担心40比特data的高位会丢失。

然后使用下面的命令行参数就可以分别传递参数值给data和data_vld。

图2 uvm命令行传递int参数

眼尖的朋友们有没有发现,这个命令行参数是不是有些眼熟?没错,之前我们聊uvm_info高级技巧的时候,用到的也是类似的命令行参数。(uvm_info高级技巧(1) ---如何屏蔽某些刷屏的啰嗦调试信息

1. 等号后面第一个参数就是component的路径,也就是当你调用get_full_name所返回的完整路径名。因为有路径限制,可以避免不同component的同名问题。类似之前讲过的,这里的路径可以使用星号通配符。

2. 第二个参数就是要赋值的变量名字,不用再担心plusargs误把“张三”和“张三丰”当作同名的问题了。

3. 第三个参数是传递的数值,这个值可以是10进制也可以是16进制、2进制、8进制,只要符合verilog语法就可以了,uvm会自动解析的。因为要符合verilog语法,所以16进制不能只写ff00,可以写32’hff00, ‘hff00, ‘shff00。除此之外,写成0xff00也是可以的。

2.2 传递string类型参数

对于string类型的数据,使用方法跟int类似。定义方法如图3所示,命令行参数如图4所示。

图3 定义string类型参数

图4 传递string类型参数

2.3 传递enum类型参数

对于plusargs传参数,如果要处理enum变量,要么放弃可读性按照int传递,要么先按照string传递然后再另外写case语句解析enum。

对于uvm命令行参数,处理enum就简单多了。闲言少叙,直接上代码,如图5所示。

图5 定义枚举类型变量

82行定义了fruit_e这个枚举类型,85行定义了fruit_e类型的枚举变量m_frt。88行声明枚举变量的时候,相比int或string类型,多了第一个参数,就是枚举变量具体的枚举类型。

命令行参数如图6所示,直接按照枚举进行传递就好了,uvm会自动解析。

图6 传递枚举类型参数

2.4 传递int数组参数

除了单个的变量,uvm也支持命令行传递数组类型的参数。如图7所示。

图7 声明数组类型变量

那么问题来了,对于这100个参数,如果传递的大部分参数都是同样的值,只有少数值不一样,难道还要写100个命令行参数吗?

答案当然是否定的。uvm命令行参数不仅支持component路径使用通配符,传递数组的时候,也可以通配。

图8 使用通配符给数组传递参数

如图8所示。先给所有的data元素赋值’hff, 然后单独给data[88]赋值1。因为命令行参数后面赋值会覆盖掉前面的赋值,所以data[88]最终传递的是1.

这里大家注意下,数组类型声明的是uvm_field_sarray_int, 传递参数的时候还是按照int的方式传递,只不过变量名字带了数组元素下表,并且支持星号通配符。

2.5 传递string数组和enum数组

string数组、enum数组的使用方法和int数组类似,没什么可说的。参照图9的声明方法和图10的命令行参数。

图9 声明string数组和enum数组

图10 传递参数给string数组和enum数组

除了上面提到的这些简单常用的参数类型,还有类似real浮点数、动态数组、关联数组等类型。大家如果有需求,可以自行参考uvm官方文档学习使用。限于篇幅,不再赘述。

2.6 uvm命令行参数什么时候生效的?

善于思考的朋友们,有没有想到一个问题:既然uvm会自动解析uvm_set_config命令行参数,那么这些参数值是什么时候传递给tb里面的变量的?会不会跟我们初始化的值冲突?

图11的示例代码,我们加上变量初始化和打印语句。

图11 调试uvm命令行参数生效时间

传递命令行参数+uvm_set_config_int = uvm_test_top.env.agt[0],data,’hdeadbeef,根据图12的测试结果可以看到,40行打印出的data值是32行初始化的,45行打印的data值是uvm_set_config_int命令行参数传递的,41行的赋值被命令行参数给覆盖掉。

也就是说,uvm_set_config_int是在new之后,build_phase之前完成的。大家在使用的时候一定要注意这个失效时间,避免多次赋值互相干扰。

图12 uvm_set_config参数生效时间测试结果

3

uvm命令行参数的限制

1. uvm命令行参数目前只能给component传递,不能给object传递。不过大家可以换一个思路,比如sequence里面要用参数mydata的话,可以传递到对应的sequencer,在sequence里面通过调用p_sequencer.mydata就可以了。

图13 间接传递uvm命令行参数给sequence

2. uvm命令行参数指定component路径的时候,如果要使用星号通配符,需要格外注意。因为uvm会把env*.sequencer匹配成env.sequencer、env0.sequencer、env0.agent.sequencer、env1.sequencer、env1.agent.sequencer等等(精通正则表达式的朋友们可以继续发散)。

3. uvm命令行参数会自动在new之后,build phase之前解析。使用的时候注意不要被覆盖了。

总结

Q哥今天给大家安利了uvm命令行传递参数的小技巧。相比plusargs,uvm命令行参数当然不是完美的,但是用到恰当的场景下,还是可以事半功倍的。大家在使用的时候,注意下上面的提到的几个问题。

好了,美好的时光总是短暂了。欢迎大家继续关注我们,共同学习,共同进步!岁月不饶人,我亦何曾饶过岁月。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 杰瑞IC验证 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档