function和task的定义(systemverilog)


在sv的class中定义的方法分为两种:.function 和 task。下面将介绍它们的特点和声明方式,以及它们之间的异同。

一、function

1.1 function的特点

  • function中不可以内置耗时语句,被调用时是立即返回的,即不消耗仿真时间;
  • 函数至少要有一个输入变量,可以无返回值或一个返回值;
  • 函数参数列表中的变量缺省数据类型为logic类型
  • 函数参数参数列表中的变量如果没有规定反向,默认是 input方向
  • 如果函数有返回值,函数的返回值类型需要在函数定义时指定,且只能通过return返回一个值,或者通过赋值给与函数同名的内部变量(用的很少);
  • 如果函数没有返回值,要在函数定义时指定为 void ;
  • 函数不可以调用task,因为task可能含有耗时语句,而函数不支持耗时语句。

1.2 function的定义

① 参数方向

参数方向可以是:

  • input
  • output
  • inout
  • ref ,即引用,后面会介绍使用方法
// input int x ;
// input int y;
function logic [15:0] myfunc1(int x, int y);
	...
endfunction

function logic [15:0] myfunc2;
	input int x;
	input int y;
	...
endfunction

//返回的参数类型logic [15:0] 
function logic [15:0] myfunc3(int a, int b, output logic [15:0] u, v);
	...
endfunction

② 返回值

有返回值时,function定义如下:

//方式一:通过将一个值赋给与函数同名的内部变量;
//这种用的很少,在SV绿皮书中介绍深拷贝章节就是用的这种做法
function [15:0] myfunc1 (input [7:0] x,y);
	myfunc1 = x * y - 1; // 
endfunction

//方式二:用return返回
function [15:0] myfunc2 (input [7:0] x,y);
	return x * y - 1; // 用return返回值
endfunction

//方式三:用ref
function void my_func3(ref [7:0]out,input [7:0] x,y);
	out = x * y - 1;
endfunction

无返回值时,function定义如下:

myprint(a); 
function void myprint (int a);
	...
endfunction

如果不想要函数的返回值,还可以使用强制转换的方式,将一个有返回值的函数丢弃其返回值,如下:

void'($cast(tr,h));
//正常情况下,如果动态转换cast失败与成功,都会有返回值的。
//当我们不关心这个返回值时,就可以采用强制转换为void形式

③ 静态和动态function

可以参考我之前的文章:静态和动态一文。

二、task

2.1 task的特点

  • task 可以内置耗时语句,也就是当调用task时,这个结果可以不是立即返回的;
  • task 既可以调用function,也可以调用task;
  • task不可以用 return 返回值;
  • task 可以在参数列表中定义参数方向,以此来返回值,可以返回一个或多个值;
  • task的参数列表中的参数,如果不规定方向,默认是input
  • 缺省的参数数据类型是 logic类型

2.2 task 的定义

① 参数方向

参数方向可以是:

  • input
  • output
  • inout
  • ref ,即引用,后面会介绍使用方法

如下,是两种带方向定义的task;

//input  a,b ;默认是input方向
//output  logic [15:0] u,
//output  logic [15:0] v;
task mytask1(a, b, output logic [15:0] u, v); 
  #10ns;
endtask
task mytask2;
	input a;
	input b;
	output logic [15:0] u;
	output logic  v;
	...
endtask

注意:虽然参数的默认方向是input,但如果你有些参数定义了方向,为了便于阅读和防止出错,那最好就把所有参数的方向都定义一下。

实例:

module traffic_lights;
	logic clock, red, green;
	parameter on = 1, off = 0;
	parameter red_tics = 350, green_tics = 200;

	initial red = off;
	initial green = off;

	always begin // waveform for the clock
		#100 clock = 0;
		#100 clock = 1;
	end
	
	always begin
		red = on; // 打开红灯
		light(red, red_tics); // 等待red_tics周期后,关闭红灯
		green = on; //  打开绿灯
		light(green, green_tics); // 等待green_tics周期后,关闭绿灯
	end

	//首先会等到tics周期的时钟,然后会将传递进来相应颜色的灯关闭
	task light (output color, input [31:0] tics);
		repeat (tics) @ (posedge clock);
		color = off; //关闭相应颜色的灯
	endtask: light
endmodule: traffic_lights

② ref的使用

以下是直接将数组传递到task中。这种方式会直接将这个a,b数组复制到堆栈中,然后再传递到方法中。

//input  [3:0][7:0] a
//input  [3:0][7:0] b [3:0]
//output [3:0][7:0] y[1:0]
task mytask3(input  [3:0][7:0] a, b[3:0], output [3:0][7:0] y[1:0]);
	...
endtask

如果数组占用内存比较小,倒还无所谓。如果是一个很大的数组,那就会影响内存了。这时候就可以使用 ref 来传递数组。ref的特点是:

  • ref是变量(但不能是net)的引用,它的值是该变量最后一次赋值的值。
  • 但是如果将一个变量连接到多个ref端口,就可能产生竞争的问题,因为多个模块的端口都有可能更新同一个变量;
  • 参数列表中如果加了ref,就不能再对齐限定方向,如ref input [7:0] arr[ ] ,这是非法的形式。
task automatic show ( const ref byte data [] );
	for ( int j = 0; j < data.size ; j++ )
	$display( data[j] ); // data can be read but not written
endtask

使用ref的优点

  • 参数传递的方式是引用,而不是复制。如果不用ref,直接引用数组,会被复制在堆栈区,影响性能;
  • 在任务中修改变量的结果对调用它的函数随时可见;
  • const ref 可以使引用的对象在子程序中不被改变;

③ 静态和动态task

关于静态和动态的可以先看我的博客:静态和动态一文。

  • 在module, interface, program 和 package的 task 默认是static的。
  • 如果一个task被声明为static,那么在整个仿真过程中,这个task都是可以被其他可见的,会一直存在。
  • 如果一个task是static/automatic 的,那么其内所有的成员变量也是static/automatic ;
  • 如果想在module内声明一个automatic的task,需要显示的加上automatic修饰,如下:
 task automatic my_auto_task(x,output y);
 	...
 endtask

④参数的缺省值

有的时候为了在原有方法中想要添加更多的控制,参数类表中的数据可能会很多,但是为了方便我们在调用时,不用给每个参数都传递一个值,这时就可以给参数列表中的参数设置默认值的方式,如下:

// j和data有默认值,K没有设置默认值
task read(int j = 0, int k, int data = 1 );
	...
endtask

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( ); // 错误声明; k 没有设置默认值
read( 1, , 7 ); // 错误声明; k 没有设置默认值

三、function 和 task 的区别

可以直接看我之前的博客:function 和 task 的区别

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小verifier

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值