完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本文讨论了一些System Verilog问题以及相关的SystemVerilog 语言参考手册规范。正确理解这些规格将有助于System Verilog用户避免意外的模拟结果。
|
|
相关推荐
11个回答
|
|
2005年,SystemVerilog被批准为硬件描述语言和硬件验证语言的标准(IEEE-1800)。从那时起,我们看到 SystemVerilog 已被我们的客户参与的几乎所有项目所采用。当我们也不断被客户问及“是模拟器对我以下代码的模拟出错了吗?”。其中的一些问题被不同的用户在调试模拟器结果一段时间后一再提及,而且无法确定是代码捅了模拟器的一个bug,还是代码本身的问题。因此,对于希望在其设计和验证环境中使用SystemVerilog的设计人员而言,正确,准确地理解语言规范非常重要。这可以为设计人员节省因调试意外结果而花费大量的时间。
在本文中,我们将讨论其中的一些问题,每个问题都带有一些示例片段或问题描述。然后,我们将展示在与其相应的IEEE-1800 语言参考手册上的规范是什么。 |
|
|
|
对上述代码的通常期望是pkg1中的所有定义在模块m1中均可见或可用的。然而这是错误的。在System Verilog 语言参考手册 2005版本中,没有明确指定链式包导入的预期行为。在System Verilog 语言参考手册 2009和更高的版本中,为避免可能出现的歧义,指定了包的导出:“默认情况下,导入到包中的声明在该包的后续导入中是不可见的。包导出的声明允许包指定要导入的声明,使其在后续的导入中可见。” 而且SystemVerilog 语言参考手册(我们在本文的其余部分中将使用IEEE-1800-2012作为参考)也阐明了正确的通配符导入和导出行为:“利用package_name :: *的形式来导出将实现把所有实际上与package_name的导入有关联的导出包给导出。所有源于package_name的名称,无论是直接导入还是通过通配符导入,都是可用的。对于候选导入但没有实际导入的符号,则是无法使用的。”以下是语言参考手册中的示例: 基于上述规范,用户的原始代码中只有在m2模块中引用的定义是可见或可用的。 |
|
|
|
a = obj.b && c; 用户得到了“访问对象为空(Null Object Access)”的运行错误,当把代码重写为 a = c && obj.b; 模拟器可以跑过这一行而且不报错。可能的原因会是什么呢? SystemVerilog 语言参考手册章节“ 11.3.5 运算符表达式短路”中著有以下的规范:“一些运算符(&&,||,->和?:)应使用短路评估;换句话说,如果运算的最终值不取决于运算表达式中的部分表达,则不应该对这部分表达式求值。” 语言参考手册专门针对运算符“ &&”和“ ||”,在“ 11.4.7逻辑运算符”章节中说明:“ && 和 ||运算符应按以下方式使用短路评估:
|
|
|
|
模拟结果如下: top.m_inst1 98710838 top.m_inst2 98710838 top.m_inst3 98710838 为什么模拟器三次例化产生了相同的随机值? SystemVerilog语言参考手册在第18.14节中详细说明了“随机稳定性”。 “ RNG(Random Number Generator 随机数生成器)为线程和对象被本地化了。因为线程或对象返回的随机值序列与其他线程或对象中的RNG无关,所以这种属性称为随机稳定性。 |
|
|
|
随机稳定性适用于以下情况:
用户可以手动为$ urandom的调用指定不同的种子,以生成不同的随机结果。例如,如果使用系统时间作为种子,则用户可以使用SystemVerilog DPI调用来获取系统时间: 请注意,使用上述解决方案,用户在不同的运行中总是会得到不同的随机结果。如果用户希望在不同的运行之间保持“随机稳定性”,则以下代码显示了另一种可能的解决方案: |
|
|
|
以下是模拟结果: 0 comb: a is: x 0 f1 call x 1 comb: a is: 1 1 f1 call x 11 comb: a is: 1 11 f1 call 1 在11时刻,always_comb块似乎被触发的原因是什么呢? 除了Verilog中常规的Always块之外,SystemVerilog引入了其他几种Always过程,包括always_comb,always_ff和always_latch。 Always_comb是对组合逻辑行为进行建模的一种非常方便的方法。使用always_comb块时,用户无需提供敏感列表。相反,SystemVerilog 语言参考手册在第9.2.2.1节中将always_comb敏感度定义为:“ always_comb的隐式敏感度列表包括在该块内或该块内调用的任何函数中读取的每个变量或选择表达式的最长静态前缀的扩展……”。 语言参考手册在9.2.2.2.2章节中再次说明了这一点:“ System Verilog always_comb过程在以下方面不同于always @ *(请参见9.4.2.2):
|
|
|
|
在System Verilog中,一个变量可以由多个过程块中的一个或多个过程语句驱动,因此在上面的代码中,从两个always @(*)对变量“ a”的驱动是有效。最后一次写操作决定对变量“ a”的赋值。但是,对于always_comb块并非如此。 System Verilog 语言参考手册第9.2.2.2节中著有“写在赋值左侧的变量不得由任何其他过程写入。” 语言参考手册在非压缩数组赋值中进一步说明到“但是,只要一个变量的独立元素所带的最长静态前缀不重叠,则允许对这些独立元素其进行多次赋值(请参见11.5.3)。”例如,一个未压缩的结构体或数组可以具有由always_comb过程对其中的一位赋值,而另一个位连续赋值或另一个always_comb过程赋值,等等。” 静态前缀的定义是递归的,定义如下:
根据上述规范,在用户代码中,always_comb块1中的最长静态前缀为“ aa [0]”,而always_comb块2中的最长静态前缀为“ aa”。它们是重叠的。为了避免此错误,用户可以将代码修改为: Localparam是一个常数表达式,因此最长的静态前缀现在在always_comb块2中为“ aa [1]”,它不再与“ aa [0]”重叠。 |
|
|
|
输出是: (2'b1x ==? 2'b10) is: x (2'b10 ==? 2'b1x) is: 1 为何模拟器会给出不同的结果? System Verilog 语言参考手册第11.4.6节中将通配相等运算符的行为指定为“通配相等运算符(==?)和不相等运算符(!=?)将其右操作数给定位置的x和z值视为通配符。左操作数中的x和z值不视为通配符。”。因此,在通配符相等运算符中,只有右侧操作数中的x和z被视为通配符。如果x和z在左操作数中,则不会将它们视为通配符。这就是上面示例中模拟器给出不同结果的原因。 SystemVerilog定义了不同种类的相等(不相等)运算符。对于逻辑相等(不等式)运算符:==和!=,如果两个操作数中都有x或z位,则该关系不明确,则结果应为1位未知值(x)。对于情况相等(不相等)运算符:===和!==,两个操作数中任意位的x或z都应包括在比较中,并且应匹配以使结果相等,因此这些运算符的结果应始终是一个已知值,可以是1或0。对于通配符等于(不等于)运算符:==?和!= ?,如果x或z位在左操作数中,则如果这些位与右操作数中的通配符进行比较不等,则结果可以是x。
仿真结果如下: 'b0 passed 'b1 fAIled 'bx passed 'bz passed 为何‘b1没通过但’bx/‘bz通过了呢? System Verilog 语言参考手册第5.7.1节提供了有关整型字符常量的规范:“如果包含s指示符,则用基数格式指定的数字应被视为带符号的整数;如果仅使用基数格式,则应将其视为无符号的整数。”,“组成无大小数字(unsized number)的位数(即一个简单的十进制数字或带有基本说明符但没有大小说明的数字)至少应为32。高位未知(X或x)或三态(Z或z)的无大小的无符号字符常量应扩展到包含字符常量的表达式的大小。”。根据上述规范,“'b1”是不带大小的无符号整数,其值为1,不等于{127 {1’b1}}。对于“'bx === {127 {1'bx}}”,模拟器需要将'bx扩展为127位(127'bx),因此这种情况下相等运算的最终结果为“ TRUE”。 以下是语言参考手册的示例: 在同一章节中,语言参考手册指定了另一种整型字符:“可以通过在单比特值前加上撇号(')来指定未定大小的单比特值,但不带基数说明符。未定值的所有位都应设置为指定位的值。”,即“ 1”定义一个所有位均为“ 1”的值。在这种情况下,如果x为{127 {1'b1}},则('1 === x)将为“ 真”。 以下是语言参考手册的示例: |
|
|
|
在SystemVerilog中,模块端口的声明有4个属性:
|
|
|
|
模拟结果是: parent: var1 is 0 child: myvar1 is 10 父类中的变量var1被赋值为0,而不是10(myvar1)。 父类中“ this.var1”的结果取决于子类中“ super.new(myvar1)”调用的执行顺序和myvar1的初始化(“ int myvar1 = 0”)。 System Verilog 语言参考手册第8.7节对类的构造函数方法进行了以下规范:“派生类的new方法应首先调用其基类构造函数[super.new(),如8.15中所述]。基类构造函数调用(如果有)完成后,应将类中定义的每个属性初始化为其显式默认值,或者如果未提供默认值,则将其初始化为未初始化的值。在属性初始化之后,应评估用户定义的构造函数中的其余代码。”根据此规范,以上代码中的执行顺序为: 1.super.new(myvar1) 2.myvar1 初始化为10 3.$display(“myvar1 is %d”,myvar1); 当super.new(myvar1)被调用时,myvar1尚未被初始化,所以其赋予整型变量的默认值(0)。 |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
733 浏览 0 评论
1132 浏览 1 评论
2512 浏览 5 评论
2846 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2693 浏览 6 评论
684浏览 7评论
keil5中manage run-time environment怎么是灰色,不可以操作吗?
997浏览 3评论
198浏览 2评论
如果mmcblk1boot0启动失败可不可以从mmcblk1boot1启动呢
189浏览 2评论
用核心板GPIO直接控制网卡1的复位信号是否会导致液晶屏初始化失败?
231浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 02:41 , Processed in 1.332669 second(s), Total 99, Slave 79 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号