验证工程师经常犯的错误(1) ​

2020-06-30 14:12:03 浏览数 (2)

“优秀的验证工程师,一定是在犯错中成长起来的。”

来源| 杰瑞IC验证(ID:Jerry_IC) |原创

作者| Q哥

泰戈尔曾经说过,“如果你对一切错误关上了门,那么真理也将将你关在门外。”

毛爷爷曾经说过,“错误是正确的先导。”

Q哥曾经说过,“优秀的验证工程师,一定是在犯错中成长起来的。”

没错,Q哥就是我本人了,你们在Jerry乱侃之余,我来正经的带各位初学者一起踩坑,让我们一起从错误中汲取营养,快速茁壮成长起来~。

来,bug们,向我开炮~

01谈一个关于class句柄传递的坑

假设现在有如下的一个类MyClass:

大家都知道,class变量本身呢只是一个句柄(有点像C语言里面的指针),没有new之前,指向空(null)。

当我们进行赋值的时候,只是传递句柄,并没有创建新的对象。比如:

看似很简单吧,但是随着验证环境的复杂,容易忽视这一点:

比如在函数调用的时候:

可以看到funcX的第一个参数是input int类型。在函数调用的时候进行了单向复制,之后在funcX里面修改b(15行),并没有影响到funcY里面a的值;在funcY里面修改a(33行),也没有传递给b。

但是第二个参数就不一样了,由于是class类型,所以函数调用传递了句柄,也就是说,funcX里面的B 和funcY里面的A指向了同一个对象,操作B.ID和操作A.ID是等效的。 16行改变了ID值,所以17行和30行打出的ID值是一样的。之后,34行改变了A.ID的值,而A和B因为指向同一个对象,所以19行打印出的B.ID和25行的A.ID是一样的。

所以,如果不希望这两个类变量指向同一个对象,需要在funcX的一开始,就手动拷贝一份。

这样之后对C的操作不会传递给A,A的操作也不影响C。

对象就像是一个提线木偶,句柄就是线!!

还是很简单?又比如在uvm port传递transaction的时候,monitor中抓transaction就发给scoreboard,如果scoreboard处理过程中,monitor又发了新的transaction,后果不堪设想啊!

再来,当我们把一个对象push进队列的时候,其实保存的也只是句柄:

// 结果是

myclass_q[0].ID = 2

myclass_q[1].ID = 2

myclass_q[2].ID = 2

所以,需要每次create一个新的对象,再放入队列,这是一个好的coding sytle:

02谈一个枚举类型拼位的坑

今天再讲一个小的枚举相关的问题代码:

Fruit_e默认是32 bit;

如果需要声明成2 bit,需要改成:

0 人点赞