systemverilog中的函数function和任务task

在verilog中,任务task和函数function之间有明显的区别,例如任务可以消耗时间而函数不能,函数里面不能带有诸如#100的时延语句或诸如@(posedge clock)、wait(ready)的阻塞语句,也不能调用任务,还有verilog中的函数必须有返回值,并且返回值必须被使用,例如用到赋值语句中。
关于verilog中任务task和函数function的具体用法和区别参考我写过的一篇文章;
verilog中的任务task和函数function用法及区别

systemveilog中函数和任务的使用方法如下:
1、一般情况下,不带参数的子程序在定义或调用时不需要带空括号();
2、begin…end为可选的,因为task…endtask和function…endfunction关键词足以定义这些程序的边界, 但是在verilog-1995中,除了单行以外的子程序是必须的;
3、可以采用简明的c语言风格,缺省的类型和方向是logic input;但是在verilog中,对参数要进行两次声明,一次是方向声明,一次是类型声明;

//systemverilog风格
task test(a, b, output bit [15:0] c, d)//其中a,b为input logic a,b; c,d为output bit [15:0];
//verilog风格
task test2;
	output [31:0] x;
	reg 	[31:0] x;
	input y;
endtask

4、可以在参数列表中指定输入参数(input),输出参数(output)、输入输出参数(inout)或引用参数(ref);只有数组变量可以在形式参数列表中声明为ref类型,而线网类型不能声明为ref类型;在使用ref时,有时候为了保护数据对象不被写入,可以同通过const方式来限定ref声明的参数
systemverilog中ref的具体用法可以参考我写的一篇文章:systemverilog中ref的用法
但是在verilog中,对参数的处理方式很简单,在子程序的开头把input或inout的值复制给本地变量,在子程序退出时,则复制output或inout的值。除了标量以外,没有任何把存储器传递给verilog子程序的方法;
5、数组可以作为形式参数传递;
6、可以为参数指定一个缺省值,如果在调用时不指明参数,则使用缺省值。

function void print_checksum(ref bit [31:0] a[], input bit [31:0] low, input int high = -1);
	bit [31:0] checksum = 0;
	if(high = -1 || high >= a.size())
		high = a.size() - 1;
	for(int i = low, i < high; i++)
		checksum += a[i];
	$display("The array checksum is %0d", checksum);
endfunction
print_checksum(a);			//a[0:size()-1]中所有元素的校验和---缺省情况
print_checksum(a, 2, 4);	//a[2:4]中所有元素的校验和
print_checksum(a, 1);		//a[1;$]中所有元素的校验和
print_checksum(a,,2)		//a[0:2]中所有元素的校验和

7、采用名字进行参数传递;

task many(input int a = 1, b = 2; c = 3, d = 4);
	$display("%0d %0d %0d %0d", a, b, c, d);
endtask
initial begin
	many(6, 7, 8, 9);	//a b c d的值分别为 6 7 8 9
	many();				//a b c d全部使用默认值
	many(.c(8));		//c的值为8,其他全部用默认值
	many(,6, , d(8));	// 1 6 3 8混合指定方式
end

8、需要注意的其他问题:

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

上述a和b参数类型会采用与前一个参数一致的ref类型,对简单的int变量使用ref并无必要,但编译器不会对此做出任何反应,可能连警告都没有,这是使用了一个错误的方向类型。
如果你在子程序中使用了非缺省输入类型的参数,应该明确指明所有参数的方向,如下所示:

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

function的独特使用规则如下:
1、可以返回数值或不返回数值,如果返回需要使用关键词return,如果不返回,则应该声明函数为void function;
2、在systemveilog中,允许函数调用任务,但是只能在由fork…join_none语句生成的线程中调用。

void函数如下;

function void print_state();
	$display("@%0t: time = %s", $time);
endfunction

3、function中可以使用return得到函数的返回值,不使用return时,与函数名字相同的变量的值就是返回值。

function bit tranmit();		
	//其他语句
	return ~ifc.cb.error;
endfunction

4、从函数返回一个数组有两种方法:
第一中方法是定义一个数组类型,然后在函数的声明中使用该类型。

typedef int fixed_array5[5];
fixed_array5 f5;
function fixed_array5 init(int start);
	foreach(init[i])
		init[i] = i + start;
endfunction
initial begin
	f5 = init(5);
	foreach(f5[i[)
		$display("fd[%0d] = %0d", i, f5[i]);
end

上述代码存在的问题是,函数init创建了一个数组,给数组的值被复制到数组f5中。如果数组很大,那么可能会引起一个性能上的问题。
第二种方法是通过引用来进行数组参数的传递。

function void init(ref int f[5], input int start);
	foreach(f[i])
		f[i] = i + start;
endfunction
int fa[5];
initial begin
	init(fa, 5);
	foreach(fa[i]
		$display("fa[%0d] = %0d", i, fa[i]);
end

从函数中返回数组的最后一种方式是将数组包装到一个类中,然后返回对象的句柄。

task的独特使用规则如下:
1、task无法通过return返回结果,因此只能通过output, inout或者ref参数来返回;
2、任务中可以使用return,提前返回;

task load_array(int len, ref int array[]);
	if(len < 0) begin
		$display("bad len");
		return;
	//其他代码
endtask

3、task可以内置耗时语句,而function不能。常见的耗时语句包括@event, wait event, #delay等。

task和function的选择建议:
1、在不耗时定义为function,在内置耗时语句时使用task;function一般用于纯粹的数字或逻辑运算,task可能被运用于需要耗时的信号采样或者驱动场景;
2、function可以被function和task调用,内置有耗时语句的task只能由task来调用;

关于task和function使用的例题:

typedef struct {
	bit [1:0] cmd;
	bit [7:0] addr;
	bit [31:0] data;
} trans;

function automatic void cp_copy(trans s, trans t);
	t = s;
endfunction

initial beign
	trans s, t;
	s.cmd = 'h1;
	s.addr = 'h10;
	s.data = 'h100;
	op_copy(t, s);
	t.cmd = 'h2;
end
//result
t.cmd = 'h2;
t.addr = 'h0;
t.data = 'h0;
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值