绿皮书《systemverilog验证——测试平台编写指南》97页,有对ref端口的简单描述:

ref端口是对变量(不能是net)的引用,它的值是该变量最后一次赋值。

并没有给出具体使用场景,那上边这句话要怎么理解呢?

使用ref声明的端口信号,在进行参数传递时,共享同一个变量存储空间,即“引用”传递进来的实参,而不是复制传递的参数。举个栗子就好理解了:

比如下边一段代码:

int array[]= {0,1,2,3,4};

//ref变量指向传入的数组变量的地址,并修改array[1]的值
task change_test(input string name, input int i, ref int array[]) 
    $display("This is a test named %s", name);
    array[1] = i; 
endtask

change_test("just a test for ref", 1, array);

上述代码将 array 数组传递进change_test任务,经过change_test操作后,外部的 数组的第二个元素array[1] 将会被修改为输入数据 i,如果没有ref关键字,那么仅仅是复制一个数组 array 传进去,外面的数组变量 array[ ] 将不会受到影响。

ref相当于一个指针,当外部实参传递进来时,task中的ref端口便指向了这个实参的地址,可直接对地址中的数据,即上述代码中的数组变量 array 进行修改,因为直接修改的是地址中的变量,所以外部的array[ ]数组也会同时被修改,而不用output修改后的值。

上述代码,如果只想引用array[ ]的值,而不想在子程序task中修改array[ ],需要加上给ref变量添加const修饰符,如果在程序修改array[ ]的值,编译器将会报错:

int array[]= {0,1,2,3,4};
int array_1;
//ref变量添加const关键词,指向传入的数组变量的地址,但是只能在程序中引用其值,不能修改
task change_test(input string name, output int i, const ref int array[])
    $display("This is a test named %s", name);
    i = array[1];
endtask

change_test("just a test for ref", array_1, array);

SystemVerilog参考手册规定,ref参数只能用于带自动存储的子程序中。即子程序快中的ref变量只能是动态变量(automatic)。

另外需要注意的是:绿皮书58页:

task sticky(ref int array[50], int a,b);

a和b的参数类型是什么呢?他们在方向上实际采用的是与前一个参数一致的ref类型。编译器并不会对此有提示报错,所以在实际使用中应该明确指明所有参数的方向。

task sticky(ref int array[50], input int a,b);

使用ref的好处是(提高运行效率)

当大量的数据需要作为input或者inout参数传递的时候,值传递效率很低,所有的数据需要在每次函数调用的时候被复制,这时数组会被复制到堆栈区,这种操作很占用内存空间,代价很高,如果参数使用 “ ref ” 前缀,可以不需要进行数据复制,可直接对原地址数据进行引用。