SystemVerilog vs C ++赋值:引用还是复制?

时间:2013-02-20 20:57:54

标签: system-verilog

我主要是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中,复制分配与参考分配的确切工作原理是什么?我很难从网络搜索中找到信息。

2 个答案:

答案 0 :(得分:6)

SystemVerilog中的类变量是引用或句柄。只有在您使用new关键字时才会创建实例。

因此,在您的示例中,obj1obj_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