当我学习 C++ 和 SV 时,我也注意到了这个问题。实际上,所有 sv 属性都在 LRM 中进行了详细描述(最新版本是 IEEE-1800-2017)。这个问题在第 8.2 章和第 13.5 章中有说明:
在第 13.5 章中:关于子程序
SystemVerilog 提供了两种将参数传递给任务和函数的方法:通过值和通过引用。参数也可以通过名称和位置来绑定。子程序参数也可以被赋予默认值,允许对子程序的调用不传递参数
总结:
子例程(包括函数和任务)参数默认按值传递,只有在添加 ref 关键字时才通过引用传递。
第8.2章:关于类和对象
面向对象的类扩展允许动态创建和销毁对象。类实例或对象可以通过对象句柄传递,这提供了安全指针功能。可以将对象声明为具有方向输入、输出、输入输出或参考的参数。在每种情况下,复制的参数都是对象句柄,而不是对象的内容。
总而言之:
对象是类的实例,对象的名称是它的引用或句柄,而不是它本身,这类似于 c++ 中的指针(通过 type *ptrname 声明)或引用(delcare by: type &refname)。对象,你操纵它的句柄。因此,当你将对象传递给没有 ref 关键字 althrough 的子程序时,它会通过值传递,但值(对象名称)是对象的句柄,而不是对象本身。因此,类是通过引用传递的您是否添加 ref 关键字。
此外,这就是为什么对于 SV 中的新人来说,流动时会出现一个非常常见的错误(来自SystemVerilog for Verification, Second Edition: A Guide to Learning the Testbench Language FeaturesJune 2008):
> task generate_transaction()
Transaction t;
mailbox mbx;
**t = new(); // wrong place**
repeat(10) begin
assert(t.randomize());
mbx.put(t);
end
错误是:只创建一个类 Transaction 的实例,因此邮箱 mbx 中的 10 个对象指向单个相同的实例。正确的方法是在需要对象时创建许多对象,换句话说,将“t = new()”放在循环块中。
> task generate_transaction()
Transaction t;
mailbox mbx;
repeat(10) begin
**t = new(); // right place**
assert(t.randomize());
mbx.put(t);
end