我主要是C ++背景。我正在跟踪我正在处理的一些SystemVerilog代码中的错误,并且惊讶地发现我认为对象复制分配实际上是一个引用分配。这个简化的代码显示了我的意思:
for (int i = 0; i < max_num; ++i)
{
var cls_obj obj1;
obj1 = obj_array[i];
some_function(obj1); // modifies the object passed in
// at this point BOTH obj1 and obj_array[i] are modified.
// some other code goes here
}
我原本只希望修改obj1
。这是因为var关键字?在SystemVerilog中,复制分配与参考分配的确切工作原理是什么?我很难从网络搜索中找到信息。
答案 0 :(得分:6)
SystemVerilog中的类变量是引用或句柄。只有在您使用new
关键字时才会创建实例。
因此,在您的示例中,obj1
和obj_array[i]
都引用(或指向)同一个实例。
默认情况下,SystemVerilog中的函数参数按值传递。但是,类句柄被视为值,因此传递给函数的任何类都通过引用有效传递。
在初始化类对象时,语言中有一个内置机制来执行浅层复制。
Packet p1;
Packet p2;
p1 = new;
p2 = new p1;
这是一个浅拷贝。对于对象,只复制句柄!
IEEE 1800-2009第8.11章中的示例对此进行了解释。
var
关键字与您看到的行为没有任何关系。事实上,我从未见过或使用var
。根据LRM,这允许在声明变量时省略类型。在你的代码中,指定了类型(cls_obj),所以我不认为它的存在正在做任何事情。
答案 1 :(得分:0)
我在学C++再学SV的时候也注意到这个问题。其实所有的sv属性都在LRM(最新版本是IEEE-1800-2017)中有详细的描述。这个问题在8.2和13.5章节有说明:
在第 13.5 章:关于子程序
<块引用>SystemVerilog 提供了两种向任务和函数传递参数的方法:按值和按引用。 参数也可以受名称和位置的约束。也可以给出子程序参数 默认值,允许调用子程序不传递参数
总结:
子程序(包括函数和任务)参数默认传值,加ref关键字才传引用。
第8.2章:关于类和对象
<块引用>面向对象的类扩展允许动态创建和销毁对象。类实例, 或对象,可以通过对象句柄传递,它提供了安全指针功能。一个对象可以 被声明为带有方向输入、输出、输入输出或参考的参数。在每种情况下,论证 复制的是对象句柄,而不是对象的内容。
总结:
对象是类的实例,对象的名称是它的引用或句柄,而不是它本身,类似于c++中的指针(按类型*ptrname声明)或引用(delcare by:类型&refname)。所以每当您操纵对象时,您就操纵了它的句柄。因此,当您将对象传递给没有 ref 关键字 althrough 的子程序时,它会通过值传递,但值(对象名称)是对象的句柄,而不是对象本身。因此,类是否通过引用传递您是否添加 ref 关键字。
另外,这就是为什么对于 SV 的新人来说,会出现一个非常常见的错误:flows(来自 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
bug 是:只创建一个类 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