函数
函数的主要用途是编写一段可以随时调用n次的代码,只需调用函数名即可,不需要任何模拟时间来执行。函数是返回类型,仅返回函数声明中提到的单个值,如果未声明则返回一个位的值。
语法:
initial
begin function_name(arguments);
endfunction <return_type(optional)> function_name(arguments);`statement1;statement2;. . statementN;
endfunction
限制:
- 函数内部的代码中不允许有#、@、wait等耗时语句
- 只能返回一个值
- 无法从函数中调用任务,因为任务允许有耗时的语句
调用函数有很多变体:
- 调用以值作为参数的函数
- 调用以变量作为参数的函数
- 使用表达式中的值调用函数
- C使用带位置参数的变量调用函数
- 调用自动函数
- 通过变量的引用调用带有变量的函数
- 调用返回类型为 void 的函数
- 通过传递数组来调用函数
- 调用具有默认值的变量的函数
- 从函数调用任务(使用 fork 和 join_none 的例外情况)
调用以值作为参数的函数
示例:
int result; initial begin result=sum(5,6); $display("\treturned from function and"); $display("\tstored the value of sum in result"); $display("\n\t@ %0t ns, value of sum is %0d",$time,result); end function int sum(int var1,var2); $display("entered into function"); return var1+var2; endfunction
在上面的示例中,函数名称是 sum,其返回类型为 int,即它仅返回一个 int 值。
流程图:
调用以变量作为参数的函数
示例:
int result,a=5,b=6; initial begin $display("\tcalling the function"); result=sum(a,b); $display("\treturned from function and"); $display("\tstored the value of sum in result"); $display("\n\t@ %0t ns, value of sum is %0d",$time,result); end function int sum(input int a,b); $display("entered into function"); return a+b; endfunction
流程图:
使用表达式中的值调用函数
示例:
initial begin $display("\n\t@ %0t ns, value of sum is %0d",$time,sum(5,6)); end function int sum(int var1,var2); $display("entered into function"); return var1+var2; endfunction
使用带位置参数的变量调用函数
示例:
initial begin result=sum(.var1(5),.var2(6)); $display("\treturned from function and"); $display("\tstored the value of sum in result"); $display("\n\t@ %0t ns, value of sum is %0d",$time,result); end function int sum(int var1,var2); $display("entered into function"); return var1+var2; endfunction
调用自动函数
语法:
function automatic function_name(arguments);
示例:
module func_automatic();int result1,result2;function int factorial_static(int var1);if(var1>=2)result1=factorial_static(var1-1)*var1;elsebeginresult1=1;endreturn result1;endfunctionfunction automatic int factorial_automatic(int var1);if(var1>=2)result2=factorial_automatic(var1-1)*var1;elsebeginresult2=1;endreturn result2;endfunctioninitialbeginresult1=factorial_static(5);result2=factorial_automatic(5);$display("factorial_static:%0d",result1);$display("factorial_automatic:%0d",result2);endendmodule: func_automatic
这里我们使用带有 automatic 关键字的函数,这意味着每当调用该函数时都会创建新的内存,而在 static 中,每当调用该函数时都会使用相同的内存。
通过变量的引用调用带有变量的函数
语法:
function automatic data_type function_name(ref arguments);
流程图:
示例:
int result,addend,augend; initial begin addend=5; augend=6; $display("\tBefore calling function -> addend = %0d , augend = %0d",addend,augend); $display("\tcalling the functions"); result=sum_without_ref(addend,augend); $display("\tafter calling function without ref -> addend = %0d, augend =%0d",addend,augend); result=sum_with_ref(addend,augend); $display("\tafter calling function with ref -> addend = %0d, augend =%0d",addend,augend); end function automatic int sum_with_ref(ref int var1,var2); int temp; $display("\n\tentered into with ref function"); temp=var1; var1=var2; var2=temp; $display("\tswapped variables by using ref "); return var1+var2; endfunction : sum_with_ref function int sum_without_ref(input int var1,var2); int temp; $display("\n\tentered into without ref function"); temp=var1; var1=var2; var2=temp; $display("\tswapped variables by without using ref "); return var1+var2; endfunction : sum_without_ref
当通过传递变量引用来调用函数时,需要提及关键字 automatic 和 ref,如上例所示。
调用返回类型为 void 的函数
语法:
//type casting
void'(function_name(arguments));
或者
//declaring the function as void type which doesn't return any value.
function void function_name(arguments);
示例:
initial begin display("\t ----output for function void return type-----"); display("\t passing string to function for displaying"); end function void display(string str); $display("%s",str); endfunction: display
通过传递数组来调用函数
语法:
data_type array_name[size];
function automatic return_type function_name(ref data_type array_name);
示例:
int array[5]; void'(fun_arr(array)); $display("\treturned from function"); $display("\n\t@ %0t ns, Array elements = %0p",$time,array); end function automatic int fun_arr(ref int arr[5]); $display("\tEntered the function"); foreach(arr[i])begin arr[i]=i+1; end $display("\t values assigned to array elements starts from 1"); return 0; endfunction
一般来说,我们不能从函数返回数组,但可以使用引用传递来传递数组,并且可以在函数中操作该数组。
调用具有默认值的变量的函数
语法:
function_name()
function <return_type> function_name(varable1=deafult_value,variable2=default_value)
示例:
initialbegin$display("\t ----output for function passing by values through variables-----");$display("\tcalling the function");result=sum();$display("\treturned from function and");$display("\tstored the value of sum in result");$display("\n\t@ %0t ns, value of sum is %0d",$time,result);endfunction int sum(input int var1=2,var2=3);$display("\n\tentered into function ");return var1+var2;endfunction: sum
在此示例中,调用函数但不传递任何值或变量,那么在这种情况下,函数所需的两个变量将采用分配给它们的默认值,即在本例中为 2 & 3 得出的总和为 5。
如果调用函数时没有值和变量,并且函数没有任何默认值,则模拟器将抛出错误。
从函数调用任务
一般来说,从函数调用任务是非法的,编译器会报错,但有一种特殊情况,可以使用 fork join_none 从函数调用任务,如下例所示。
示例:
initial begin$display("\t@ %0t ns, In the initial block",$time); $display("\tcalling function"); #1 void'(function_call); end function function_call; fork $display( "\t@ %0t ns I'm in function",$time); $display("\t@ %0t ns, calling task from func",$time); task_call; join_none endfunction task task_call; #1 $display( "\t@ %0t ns , I'm in task",$time); #1 $display("\t@ %0t ns,leaving from task",$time); endtask
流程图:
任务
任务(task)与函数类似,但任务可以计算多个变量并使用输出或 inout 语句返回它们,但不像函数那样必需,即任务不是返回类型,并且任务能够具有诸如 #、@、等待。任务也可以调用另一个任务和函数。
语法:
task_name(arguments); task task_name(arguments);
statement1;
statement2;
.
.
statementN;
endtask
限制:
- 任务不可综合
流程图
automatic task
每当声明为 automatic task 时,每次调用该任务时,模拟器都会分配新的内存。一般来说,任务在模块内部是静态的,要使其自动执行,需要添加 automatic 关键字,如下所示。
语法:
task automatic task_name()
示例:
task automatic factorial_automatic(int var1);#1;if(var1>=2)beginfactorial_automatic(var1-1);result=result*var1;endelsebeginresult=1;->a;endendtaskinitialbeginforkfactorial_static(5);factorial_automatic(5);joinforkwait(a.triggered);$display("@ %0t ns , factorial_automatic:%0d",$time,result);end
流程图:
从任务中调用函数
示例:
initialbegin$display("\t ----output for func from task----");$display("\t@ %0t ns, In the initial block",$time);$display("\tcalling task");task_sum;$display("\treturned to initial from function");end task task_sum;#1 $display( "\t@ %0t ns , I'm in task",$time);$display("\tcalling func inside a task");#1 void'(function_sum);$display("\treturned to task from function");endtaskfunction function_sum;$display( "\t@ %0t ns I'm in function",$time);endfunction
从函数中调用任务是非法的,但从任务中调用 func 是正常的,因为函数没有任何耗时的语句。
流程图:
全局任务
如果一个任务是在模块和类之外声明的,则该任务被称为全局任务,默认的全局任务本质上是静态的。该全局任务可以从任何模块调用,通过以下示例可以更好地理解。
示例:
task mul(input int var1,var2,output int res);#1 res=var1*var2;endtaskmodule task1();int multiplicand=5,multiplicator=6,result;initialbegin$display("\t ----output of global task----");mul(multiplicand,multiplicator,result);$display("\t @ %0t ns , %0d X %0d = %0d",$time,multiplicand,multiplicator,result);endendmodulemodule task2();int r;initialbegin#2 mul(7,8,r);$display("\t @ %0t ns , 7 X 8 = %0d",$time,r);endendmodule
禁用任务
可以通过在任务名称中使用关键字 disable 来禁用任务,这会在调用禁用时停止该特定任务。
示例:
module disable_task();initialbegin$display("\t ----output of disable task----");forkdisplay_task();#20 disable display_task.task_A;joinendtask display_task();begin : task_A$display("\t @ %0t ns , task_A initiated",$time);#30 $display("\t @ %0t ns , task_A finished",$time);end :task_Abegin : task_B$display("\t @ %0t ns , task_B initiated",$time);#10 $display("\t @ %0t ns , task_B finished",$time);end :task_Bendtaskendmodule