systemverilog中的参数传递——ref、input、output

文章讲述了在SystemVerilog中,静态数组和类作为参数时,input、output和ref关键字的传递方式差异,以及它们对函数调用前后值的影响。input是值传递,output是反向地址传递,ref则是标准地址传递且更高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、 静态数组作为参数

        SystemVerilog中的静态数组、动态数组、队列都是用一块内存存放,而他们的名字作为该内存的地址,这点和c一致,但sv中没有指针的概念。

        传递这种大片内存的值一般只有两种规则:
                1.地址传递,函数内部修改可以改变函数调用的值
                2.值传递,将整片空间复制一份,函数内部修改不会改变函数调用的值

        但是,sv中里面关键字有三个:input、output、ref。具体哪个对应哪个,下面来看一下,以静态数组作为模板来试。

function void run();
  int r[2];
  r[0]=1;
  r[1]=2;
  f(r);
  $display("%0x %0x",r[0],r[1]);
 endfunction

1.1 input

当函数类型为input时。

function void f(input int a[2]);
  a[0]=3;
 endfunction

输出结果:1 2

具体过程如下:
        1.函数调用之前,内存里只有r数组的空间
        2.函数调用之后,会将r拷贝一份到a, 函数里面用的都是a这份空间
        3.函数调用之后,复制后,修改的是a这份空间
        4.函数返回之后,a空间会被释放掉,所以r的值并没有被修改

        因此,input是标准的值传递

1.2 output

当函数类型为output时。

function void f(output int a[2]);
  a[0]=3;
 endfunction

输出结果是:3 0

具体过程如下:
        1.函数调用之前,内存里只有r数组的空间
        2.函数调用 之后,会新建一份a数组,注意这里并不会把r的值传进来,函数里面用的是a这份空间
        3.函数调用之后,赋值后,修改的是a这份空间
        4.函数返回之后,会将r指向a空间,而原来的r指向的空间会被释放掉,所以r的值都被修改了

        因此,output 采用的是地址传递,确切的说是反向地址传递,数组共有两份,函数内部看到的是新建的一份,并传递给函数调用处。所以函数调用前是第一份,函数调用后看到的是新建的那份

1.3 ref

当函数是ref时。

function void f(ref int a[2]);
  a[0]=3;
 endfunction

输出结果是: 3 2

具体过程如下:
        1.函数调用前,内存里只有r数组的空间
        2.函数调用之后,会将a指向r所在的空间,函数里面用的都是这份空间
        3.函数调用之后,赋值后,修改的是这份空间的值,所以a和r的值都被修改啦
        4.函数返回后,所以r的值只有部分被修改
        因此,ref采用的是标准的地址传递,只有一份数组,函数内部和调用出都是访问该空间

        对比来看,input是将函数外面的值传递到函数里面,调用之后,函数里面的值就被丢弃了;output是将函数里面的值传递到函数外面来,调用之后,函数外面的值就被丢弃了;ref是函数内部和外部看到的是同一份值,哪里都会被修改。另外,可以看出,采用ref关键字,占用 的空间内存是最小的,因为只有一份数组,这样能提高效率。

动态数组或队列作为参数

        如果传递的是动态数组或队列,其结果是一模一样的,不另外作说明。

3 类作为参数

下面展示一些 内联代码片

class c;
     int v0;
     int v1;
 endclass

function void run();
     c c0;
     c0 = new();
     c0.v0 = 1;
     c0.v1 = 2;
     f(c0)
     $display(" %0x %0x ", c0.v0 ,c0.v1);
 endfunction
 
 function voidf(input /output ref c c0);
      c0.v0 =3;
 endfunction

输出结果是:
        1.input : 3 2
        2.output :报null point 错误
        3.ref: 3 2

        可以看出,如果是传递类的话,使用input 和ref 的结果是一样 的,而output和数组 的结果是一样 的

### SystemVerilog Task 中 `ref` 和 `output` 参数的区别 在SystemVerilog的任务定义中,参数可以通过三种方式传递:`input`, `output`, 或者 `ref`。每种类型的参数具有不同的行为和用途。 #### Output 参数 当参数被声明为 `output` 类型时,在任务内部对该参数的赋值会反映到调用该任务的作用域内。但是,`output` 只能用于单向的数据传输——即从任务内部传回到外部作用域。这意味着在进入任务之前,`output` 参数不会携带任何来自调用端的有效初始值[^1]。 ```systemverilog task example_task(output reg [7:0] data); // 修改data变量并将新值返回给调用方 data = 8'hAA; endtask : example_task ``` #### Ref 参数 相比之下,`ref` 是一种双向引用机制。它允许任务读取并写入实际传递给它的变量的内容。因此,如果希望既能获取原始值又能更新这个值,则应使用 `ref` 关键字来声明相应的形参。需要注意的是,为了防止意外修改全局状态或其他模块中的数据成员,只有局部自动变量、静态变量或显式指定为可变的对象才能作为 `ref` 实参与之匹配。 ```systemverilog module top(); logic [7:0] var; initial begin var = 8'hFF; call_ref_task(var); $display("After calling ref task, var=%h", var); // 输出var的新值 end task automatic call_ref_task(ref logic [7:0] value); // 访问value变量的当前值,并可能对其进行更改 $display("Inside ref task, before modification, value=%h", value); value = ~value; // 对其求反操作 $display("Inside ref task, after modification, value=%h", value); endtask : call_ref_task endmodule : top ``` 通过上述例子可以看出: - 使用 `output` 的情况下,仅能在过程结束之后看到变化的结果; - 而对于 `ref` 来说,不仅可以在过程中实时观察到改变后的数值,而且这种改动也会立即影响到原位置上的对象实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值