(四)任务和函数

过程语句

SystemVerilog从C和C++中引入了很多操作符和语句。如for循环中定义循环变量,它的作用范围仅限于循环内部,从而有助于避免一些代码漏洞;自动递增符“i++”和自动递减符“i–”既可以作为前缀,也可以作为后缀。如果在begin或fork语句中使用标识符,那么在相对应的end或join语句中可以放置相同的标号,这使得程序块的首尾匹配更加容易。你也可以把标识符放在SystemVerilog的其他结束语句里,例如endmodule、endtask、endfunction。

initial 
begin:example 
	integer array[10],sum,j;
	//在for语句中声明i
	forint i=0;i<10;i++)			//i递增
		array[i]=i;
	//把数组里的元素相加
	sum=array[9];
	j=8;
	do
		sum+=array[j];				//累加
	while(j--;					//判断j=0是否成立
end:example

同时System Verilog为循环功能增加了两个新语句。第一个是continue,用于在循环中跳过本轮循环剩下的语句而直接进入下一轮循环。第二个是break,用于终止并跳出循环。

任务、函数及void函数

任务(task)和函数(function)的区别:

  • 任务可以消耗时间而函数不能(函数里面不能带有注入#100的时延语句或诸如@(posedge clock)、wait(ready)的阻塞语句);
  • 函数也不能调用任务,单任务可以调用函数和其他任务;
  • 函数必须有返回值,并且返回值必须被使用,例如用到赋值语句中;任务则不必(System Verilog对这条限制稍有放宽,允许函数调用任务,但只能在由fork….join_none语句生成的线程中调用)。

(注:如果有一个不消耗时间的svstemverilog任务,应该把它定义成void函数,这种函数没有返回值。这样它就能被任有任务或函数所调用了。从最大灵活性的角度考虑,所有用于调试的子程序都应该定义成void函数而非任务,以便于被任何其他任务或函数所调用。)

在SystemVerilog中,如果你想调用函数并且忽略它的返回值,可以使用void进行结果转换,如下所示。

void'($fscanf(file,"8d",i));

任务和函数概述

一般情况下,不带参数的子程序在定义或调用时并不需要带空括号()。
在System Verilog中,begin…end块变成了可选,而在Verilog-1995中则对单行以外的子程序都是必须的。task/endtask和function/endfunction的关键词已经足以定义这些子程序的边界了。

task multiple lines;
	$display("First line");
	$display("Second line"); 
endtask:multiple lines

高级参数的类型

Verilog对参数的处理方式很简单:在子程序的开头把input和inout的值复制给本地变量,在子程序退出时则复制 output和inout的值。除了标量以外,没有任何把存储器传递给Verilog子程序的办法。

在System Verilog中,参数的传递方式可以指定为引用而不是复制,这种ref参数类型比input、output或inout更好用。

//使用ref和const传递数组
function void print_checksum(const ref bit[31:0]a[]);
	bit[31:0]checksum=0;
	for(inti=0;i<a.size();i++)
		checksum^=a[i];
	$display("The array checksum is $0d",checksum);
endfunction

(注:1、System Verilog 允许不带ref进行数组参数的传递,这时数组会被复制到堆栈区里。这种操作的代价很高,除非是对特别小的数组;2、System Verilog的语言参考手册(LRM)规定了ref参数只能被用于带自动存储的子程序中。如果你对程序或模块指明了automatic属性,则整个子程序内部都是自动存储的。3、上例用到了const 修饰符。虽然数组变量a指向了调用程序中的数组,但子程序不能修改数组的值,否则编译器将报错。)

参数的缺省值

当测试程序越来越复杂时,你可能希望在不破坏已有代码的情况下增加额外的控制。在下例的函数中,可能希望把数组中间部分元素的校验和打印出来,但是又不希望改写代码,在System Verilog中,可以为参数指定一个缺省值,如果在调用时不指明参数,则使用缺省值

function void print checksum(ref bit [31:0] a[], 
								input bit[31:0]low=0, 
								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

一个常见的错误

在编写子程序代码时往往会忘记,在缺省的情况下参数的类型是与其前一个参数相同的,而第一个参数的缺省类型是单比特输入。

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

a和b的参数类实际采用的是与上一个参数一致的reg类型,对简单的int变量使用ref通常并无必要,但编译器不会对此做出任何反应,所以不会意识到正在使用一个错误的方向类型。如果在子程序中使用了非缺省输入类型的参数,应该明确指的所着参数的方向,如下例:

task sticky(ref int array[50],
			input int a,b);		//明确指定方向

子程序的返回

Verilog中子程序的结束方式比较简单;当你执行完子程序的最后一条语句,程序就会返回到调用子程序的代码上。此外,函数还会返回一个值,该值被赋给与函数同名的变量。

返回语句

System Verilog 增加了return语句,使子程序中的流程控制变得更方便。

从函数返回一个数组

Verilog的子程序只能返回一个简单值,例如比特、整数或是向量。在System Verilog中,函数可以采用多种方式返回一个数组

  • 第一种方式是定义一个数组类型,然后在函数的声明中使用该类型。
typedef int fixed_array5[5];
fixed_array5 f5;
function fixed arravs init(int start);
	foreach(init[i])
		init[i]=i+start;
	endfunction 

initial begin 
	f5=init(5);
	foreach(f5[i])
		$display("f5[%0d]=%0d",i,f5[i]);
end

(注:使用上述代码的一个问题是,函数init创建了一个数组,该数组的值被拷贝到数组f5中。如果数组很大,那么可能会引起一个性能上的问题)

另一种方式是通过引用来进行数组参数的传递。以ref参数的形式将数组传递到函数里,如下例所示。

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[sod]=80d",i,fa[i]);
end

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

局部数据的存储

Verilog最初的目的是用来描述硬件。因此语言中的所有对象都是静态分配的。特别是,子程序参数和局部变量是被存放在固定位置的,而不像其他编程语言那样存放在堆栈区里。

//静态初始化的漏润
program initialization;//有漏洞的版本
	task check_bus;
		repeat(5)@(posedge clock);
		if(bus cmd=='READ)begin
			logic[7:0]local addr=addr<<2;//有漏洞,何时对localaddr赋初值?
			$display("Local Addr=8h",local_addr);
		end 
	endtask 
endprogram

一般为了防止初始化的漏洞,将声明和初始化分开即可;或者将程序块声明为automatic,这样就避免了一开始就有初值;如下所示:

logic[7:0]local addr;
local_addr=addr<2;

这篇笔记参考《system verilog验证》绿皮书整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数字ic攻城狮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值