SystemVerilog中子程序调用与参数传递

在SystemVerilog中新定义一种端口类型 "ref "传递变量地址而非变量本身。

1. 传递值
  • 传递值是子程序传递参数的默认机制。这种传递机制将每个参数拷贝到子程序区域,如果子程序是 automatic 类型,那么子程序会在其本身的堆栈中保留一个局部的参数副本。参数在子程序内部的修改对外部不可见。

  • 参数巨大时使用该方式传递参数是不可取的。

    // 传递值的方式如下:
    function automatic int crc(bype packet[1000:1]);
    	for (int i = 1; i <= 1000; i++)begin
    		crc ^= packet[i];
    	end
    endfunction
    
2. 传递引用 (ref)
  • ref参数类似于inout参数,只是inout参数被复制两次:一次在子程序被调用时,从外部进入子程序内部;一次在子程序返回时,从子程序内部传递到外部。 传递对象句柄也不例外,并且在作为ref或inout参数传递时具有类似的语义。 因此,除了修改对象的内容之外,对象句柄的引用还允许对对象句柄的更改(例如,分配新对象)。

    没ref传递的是句柄,不能修改句柄,有ref,传递的是句柄的地址,可以修改句柄。

    function void create( ref transcation tr)
         tr = new();    // 分配对象;
         tr.addr = 42;
    endfunction
    
  • 通过引用进行参数传递时并不会将变量本身传递到子程序区域,而是传递原始参数的引用 (与C中的指针类似),子程序可以通过引用访问参数数据。

  • 通过引用传递的参数应与等效数据类型匹配。

  • 不允许进行转换(No casting)。

  • 使用关键字 ref 声明传递参数的方式是引用而非其他。

  • 对于具有静态生命的子程序,通过引用的方式传递参数是非法的。

    语法格式如下:
    subroutine( ref type argument );

    	// 传递引用的方式如下:
    	function automatic int crc (ref bype packet[1000:1]);
    		for (int i = 1; i <= 1000; i++)begin
    			crc ^= packet[i];
    		end
    	endfunction
    
  • 当参数通过引用传递时,调用者和子程序共享参数的相同表示方式;因此,在调用者或子程序中对参数所做的任何更改都相互可见。 通过引用传递的变量赋值的语义是在子程序之外立即看到对其的更改(在子程序返回之前)。

  • 因通过引用传递的变量可能是自动变量,故不应在任何禁止自动变量的上下文中使用ref参数。

只有以下引用传递参数是合法的

  1. 一个变量;
  2. 一个类的属性;
  3. 一个非打包结构的成员(unpacked structure);
  4. 一个非打包数组的元素(unpacked array);
  • 通过引用传递的动态数组,队列和关联数组的元素可能会从数组中删除,或者在调用子程序完成之前可能会调整数组的大小。
  • 通过引用传递的特定数组元素应继续存在于被调用子程序的范围内,直到它们完成。 如果在进行更改之前从阵列中删除了那些数组元素,那么被调用子程序对数组元素值所做的更改将不会在这些子程序的范围之外可见。这种引用被称为是过时的引用

对可变大小的数组进行以下操作将导致对该数组的元素的现有引用变为过时的引用

  1. 动态数组显式或者隐式使用new[]进行数组大小的重定义;
  2. 动态数组使用delete()方法进行删除;
  3. 使用delete()方法删除被引用的关联数组的元素;
  4. 包含引用元素的队列或动态数组通过赋值更新;
  5. 使用队列方法删除引用的队列元素;
  • 通过引用传递参数是一个唯一的参数传递限定符,不同于输入,输出或输入。 将ref与任何其他方向限定符组合应该是非法的。例如:

    task automatic incr( ref input int a );   // 非法
    
  • 为了保护引用传递的参数不被子程序修改,const 限定符可以与ref一起使用,表示参数虽然通过引用传递,但它是一个只读变量;

    • 如果引用参数使用const修饰,那么该不允许子程序修改, 子程序尝试修改时编译器报错。
    task automatic show ( const ref byte data [] );
    	for ( int j = 0; j < data.size ; j++ )
    		$display( data[j] );    // 数据只读
    endtask
    
3. 参数默认值
  • 为了处理常见情况或允许使用未使用的参数,SystemVerilog允许子程序为每个单数参数指定默认值。

语法格式:
subroutine( [ direction ] [ type ] argument = default_expression);

task read(int j = 0, int k, int data = 1 );
	...
endtask

// call method.
read( , 5 );     // is equivalent to read( 0, 5, 1 );
read( 2, 5 );    // is equivalent to read( 2, 5, 1 );
read( , 5, );    // is equivalent to read( 0, 5, 1 );
read( , 5, 7 );  // is equivalent to read( 0, 5, 7 );
read( 1, 5, 2 ); // is equivalent to read( 1, 5, 2 );
read( );         // error; k has no default value
read( 1, , 7 );  // error; k has no default value

你可能感兴趣的:(SV学习笔记)